diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 5e94a83a3a5b97fac22688be4d79e2bfab01082c..79dfab50c8e434a6cdbe5dad6d7a6544c622902e 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -13,28 +13,28 @@ tasks:
- test: |
cd zig/build
bin/zig test ../test/stage1/behavior.zig
- bin/zig test ../std/special/compiler_rt/index.zig
+ bin/zig test ../std/special/compiler_rt.zig
bin/zig test ../test/stage1/behavior.zig --library c
- bin/zig test ../std/special/compiler_rt/index.zig --library c
+ bin/zig test ../std/special/compiler_rt.zig --library c
bin/zig test ../test/stage1/behavior.zig --release-fast
- bin/zig test ../std/special/compiler_rt/index.zig --release-fast
+ bin/zig test ../std/special/compiler_rt.zig --release-fast
bin/zig test ../test/stage1/behavior.zig --release-fast --library c
- bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c
+ bin/zig test ../std/special/compiler_rt.zig --release-fast --library c
bin/zig test ../test/stage1/behavior.zig --release-small --library c
- bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c
+ bin/zig test ../std/special/compiler_rt.zig --release-small --library c
bin/zig test ../test/stage1/behavior.zig --release-small
- bin/zig test ../std/special/compiler_rt/index.zig --release-small
+ bin/zig test ../std/special/compiler_rt.zig --release-small
bin/zig test ../test/stage1/behavior.zig --release-safe
- bin/zig test ../std/special/compiler_rt/index.zig --release-safe
+ bin/zig test ../std/special/compiler_rt.zig --release-safe
bin/zig test ../test/stage1/behavior.zig --release-safe --library c
- bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c
+ bin/zig test ../std/special/compiler_rt.zig --release-safe --library c
# TODO enable all tests
#bin/zig build --build-file ../build.zig test
# TODO integrate with the download page updater and make a
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e2cb5b9d40f3ed051d4e09171dc9f9bd6c3b92b..881f432c619e52667cb0ce862e00457f9d455914 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -442,7 +442,7 @@ set(ZIG_CPP_SOURCES
set(ZIG_STD_FILES
"array_list.zig"
- "atomic/index.zig"
+ "atomic.zig"
"atomic/int.zig"
"atomic/queue.zig"
"atomic/stack.zig"
@@ -452,17 +452,17 @@ set(ZIG_STD_FILES
"buffer.zig"
"build.zig"
"build/fmt.zig"
+ "c.zig"
"c/darwin.zig"
"c/freebsd.zig"
- "c/index.zig"
"c/linux.zig"
"c/netbsd.zig"
"c/windows.zig"
"coff.zig"
+ "crypto.zig"
"crypto/blake2.zig"
"crypto/chacha20.zig"
"crypto/hmac.zig"
- "crypto/index.zig"
"crypto/md5.zig"
"crypto/poly1305.zig"
"crypto/sha1.zig"
@@ -470,8 +470,8 @@ set(ZIG_STD_FILES
"crypto/sha3.zig"
"crypto/x25519.zig"
"cstr.zig"
+ "debug.zig"
"debug/failing_allocator.zig"
- "debug/index.zig"
"dwarf.zig"
"dynamic_library.zig"
"elf.zig"
@@ -488,25 +488,25 @@ set(ZIG_STD_FILES
"event/net.zig"
"event/rwlock.zig"
"event/rwlocked.zig"
+ "fmt.zig"
+ "fmt/errol.zig"
"fmt/errol/enum3.zig"
- "fmt/errol/index.zig"
"fmt/errol/lookup.zig"
- "fmt/index.zig"
"fmt/parse_float.zig"
+ "hash.zig"
"hash/adler.zig"
"hash/crc.zig"
"hash/fnv.zig"
- "hash/index.zig"
"hash/siphash.zig"
"hash_map.zig"
"heap.zig"
- "index.zig"
"io.zig"
"io/seekable_stream.zig"
"json.zig"
"lazy_init.zig"
"linked_list.zig"
"macho.zig"
+ "math.zig"
"math/acos.zig"
"math/acosh.zig"
"math/asin.zig"
@@ -514,10 +514,11 @@ set(ZIG_STD_FILES
"math/atan.zig"
"math/atan2.zig"
"math/atanh.zig"
- "math/big/index.zig"
+ "math/big.zig"
"math/big/int.zig"
"math/cbrt.zig"
"math/ceil.zig"
+ "math/complex.zig"
"math/complex/abs.zig"
"math/complex/acos.zig"
"math/complex/acosh.zig"
@@ -530,7 +531,6 @@ set(ZIG_STD_FILES
"math/complex/cos.zig"
"math/complex/cosh.zig"
"math/complex/exp.zig"
- "math/complex/index.zig"
"math/complex/ldexp.zig"
"math/complex/log.zig"
"math/complex/pow.zig"
@@ -553,7 +553,6 @@ set(ZIG_STD_FILES
"math/frexp.zig"
"math/hypot.zig"
"math/ilogb.zig"
- "math/index.zig"
"math/inf.zig"
"math/isfinite.zig"
"math/isinf.zig"
@@ -578,50 +577,51 @@ set(ZIG_STD_FILES
"math/tanh.zig"
"math/trunc.zig"
"mem.zig"
- "meta/index.zig"
+ "meta.zig"
"meta/trait.zig"
"mutex.zig"
"net.zig"
+ "os.zig"
"os/child_process.zig"
"os/darwin.zig"
"os/darwin/errno.zig"
"os/epoch.zig"
"os/file.zig"
+ "os/freebsd.zig"
"os/freebsd/errno.zig"
- "os/freebsd/index.zig"
"os/get_app_data_dir.zig"
"os/get_user_id.zig"
- "os/index.zig"
+ "os/linux.zig"
"os/linux/arm64.zig"
"os/linux/errno.zig"
- "os/linux/index.zig"
"os/linux/vdso.zig"
"os/linux/x86_64.zig"
+ "os/netbsd.zig"
"os/netbsd/errno.zig"
- "os/netbsd/index.zig"
"os/path.zig"
"os/time.zig"
"os/uefi.zig"
+ "os/windows.zig"
"os/windows/advapi32.zig"
"os/windows/error.zig"
- "os/windows/index.zig"
"os/windows/kernel32.zig"
"os/windows/ntdll.zig"
"os/windows/ole32.zig"
"os/windows/shell32.zig"
- "os/windows/tls.zig"
"os/windows/util.zig"
"os/zen.zig"
"pdb.zig"
"priority_queue.zig"
- "rand/index.zig"
+ "rand.zig"
"rand/ziggurat.zig"
"segmented_list.zig"
"sort.zig"
"special/bootstrap.zig"
"special/bootstrap_lib.zig"
+ "special/bootstrap_windows_tls.zig"
"special/build_runner.zig"
"special/builtin.zig"
+ "special/compiler_rt.zig"
"special/compiler_rt/addXf3.zig"
"special/compiler_rt/aulldiv.zig"
"special/compiler_rt/aullrem.zig"
@@ -656,7 +656,6 @@ set(ZIG_STD_FILES
"special/compiler_rt/floatuntidf.zig"
"special/compiler_rt/floatuntisf.zig"
"special/compiler_rt/floatuntitf.zig"
- "special/compiler_rt/index.zig"
"special/compiler_rt/muloti4.zig"
"special/compiler_rt/multi3.zig"
"special/compiler_rt/truncXfYf2.zig"
@@ -674,10 +673,11 @@ set(ZIG_STD_FILES
"special/test_runner.zig"
"spinlock.zig"
"statically_initialized_mutex.zig"
+ "std.zig"
"testing.zig"
"unicode.zig"
+ "zig.zig"
"zig/ast.zig"
- "zig/index.zig"
"zig/parse.zig"
"zig/parse_string_literal.zig"
"zig/render.zig"
diff --git a/build.zig b/build.zig
index 756ec5370885c30afb560c09bdac8e50e82e99fc..6acf08a0e5f238e8d609ac87bf2d5d3ce53c8e4b 100644
--- a/build.zig
+++ b/build.zig
@@ -115,9 +115,9 @@ pub fn build(b: *Builder) !void {
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
- test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes));
- test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", modes));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes));
test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes));
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 9dc0a31b23b3cef28727e4b08d59007420c3cabc..b816d652896583e338b0e748ba95aef114ce8da9 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -6116,7 +6116,7 @@ test "main" {
{#header_close#}
{#header_open|@frameAddress#}
-
{#syntax#}@frameAddress(){#endsyntax#}
+ {#syntax#}@frameAddress() usize{#endsyntax#}
This function returns the base pointer of the current stack frame.
@@ -6482,17 +6482,18 @@ test "call foo" {
{#header_close#}
{#header_open|@returnAddress#}
- {#syntax#}@returnAddress(){#endsyntax#}
+ {#syntax#}@returnAddress() usize{#endsyntax#}
- This function returns a pointer to the return address of the current stack
- frame.
+ This function returns the address of the next machine code instruction that will be executed
+ when the current function returns.
The implications of this are target specific and not consistent across
all platforms.
- This function is only valid within function scope.
+ This function is only valid within function scope. If the function gets inlined into
+ a calling function, the returned address will apply to the calling function.
{#header_close#}
{#header_open|@setAlignStack#}
@@ -6785,7 +6786,6 @@ pub const TypeId = enum {
Enum,
Union,
Fn,
- Namespace,
Block,
BoundFn,
ArgTuple,
@@ -6820,7 +6820,6 @@ pub const TypeInfo = union(TypeId) {
Enum: Enum,
Union: Union,
Fn: Fn,
- Namespace: void,
BoundFn: Fn,
ArgTuple: void,
Opaque: void,
@@ -6829,18 +6828,18 @@ pub const TypeInfo = union(TypeId) {
pub const Int = struct {
is_signed: bool,
- bits: u8,
+ bits: comptime_int,
};
pub const Float = struct {
- bits: u8,
+ bits: comptime_int,
};
pub const Pointer = struct {
size: Size,
is_const: bool,
is_volatile: bool,
- alignment: u32,
+ alignment: comptime_int,
child: type,
pub const Size = enum {
@@ -6851,7 +6850,7 @@ pub const TypeInfo = union(TypeId) {
};
pub const Array = struct {
- len: usize,
+ len: comptime_int,
child: type,
};
@@ -6863,7 +6862,7 @@ pub const TypeInfo = union(TypeId) {
pub const StructField = struct {
name: []const u8,
- offset: ?usize,
+ offset: ?comptime_int,
field_type: type,
};
@@ -6884,7 +6883,7 @@ pub const TypeInfo = union(TypeId) {
pub const Error = struct {
name: []const u8,
- value: usize,
+ value: comptime_int,
};
pub const ErrorSet = struct {
@@ -6893,7 +6892,7 @@ pub const TypeInfo = union(TypeId) {
pub const EnumField = struct {
name: []const u8,
- value: usize,
+ value: comptime_int,
};
pub const Enum = struct {
@@ -8167,17 +8166,18 @@ coding style.
-
- If {#syntax#}x{#endsyntax#} is a {#syntax#}struct{#endsyntax#} (or an alias of a {#syntax#}struct{#endsyntax#}),
- then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}.
+ If {#syntax#}x{#endsyntax#} is a {#syntax#}type{#endsyntax#}
+ then {#syntax#}x{#endsyntax#} should be {#syntax#}TitleCase{#endsyntax#}, unless it
+ is a {#syntax#}struct{#endsyntax#} with 0 fields and is never meant to be instantiated,
+ in which case it is considered to be a "namespace" and uses {#syntax#}snake_case{#endsyntax#}.
-
- If {#syntax#}x{#endsyntax#} otherwise identifies a type, {#syntax#}x{#endsyntax#} should have {#syntax#}snake_case{#endsyntax#}.
+ 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#}.
-
- 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#}.
-
- -
- If {#syntax#}x{#endsyntax#} is otherwise callable, then {#syntax#}x{#endsyntax#} should be {#syntax#}camelCase{#endsyntax#}.
+ If {#syntax#}x{#endsyntax#} is otherwise callable, then {#syntax#}x{#endsyntax#} should
+ be {#syntax#}camelCase{#endsyntax#}.
-
Otherwise, {#syntax#}x{#endsyntax#} should be {#syntax#}snake_case{#endsyntax#}.
@@ -8203,7 +8203,9 @@ const const_name = 42;
const primitive_type_alias = f32;
const string_alias = []u8;
-const StructName = struct {};
+const StructName = struct {
+ field: i32,
+};
const StructAlias = StructName;
fn functionName(param_name: TypeName) void {
@@ -8231,7 +8233,9 @@ const xml_document =
\\
\\
;
-const XmlParser = struct {};
+const XmlParser = struct {
+ field: i32,
+};
// The initials BE (Big Endian) are just another word in Zig identifier names.
fn readU32Be() u32 {}
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index de956f15250a32a7d88e16150118f3e2a12d6b8c..478edce020011ef9825520f2d6ec6707bcf4ff4d 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -47,7 +47,7 @@ pub const ZigCompiler = struct {
var lazy_init_targets = std.lazyInit(void);
- fn init(loop: *event.Loop) !ZigCompiler {
+ pub fn init(loop: *event.Loop) !ZigCompiler {
lazy_init_targets.get() orelse {
Target.initializeAll();
lazy_init_targets.resolve();
@@ -533,7 +533,7 @@ pub const Compilation = struct {
const basename = std.os.path.basename(root_src);
comp.root_package = try Package.create(comp.arena(), dirname, basename);
- comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "index.zig");
+ comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "std.zig");
try comp.root_package.add("std", comp.std_package);
} else {
comp.root_package = try Package.create(comp.arena(), ".", "");
diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig
index 0a7f63b4f17c2a476f6473ccede8e4a8d3e047b4..8f859a82cea502e814b8b2e738f1be0b96fc8d78 100644
--- a/src-self-hosted/introspect.zig
+++ b/src-self-hosted/introspect.zig
@@ -11,7 +11,7 @@ pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![
const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
errdefer allocator.free(test_zig_dir);
- const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "index.zig" });
+ const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "std.zig" });
defer allocator.free(test_index_file);
var file = try os.File.openRead(test_index_file);
diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig
index 7d611bb78793a286110ff4cb1e21de372ba3bdb1..4c9fb58a18fd59273e17bd5e30b675a6ed73f797 100644
--- a/src-self-hosted/type.zig
+++ b/src-self-hosted/type.zig
@@ -39,7 +39,6 @@ pub const Type = struct {
Id.ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),
Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),
- Id.Namespace => @fieldParentPtr(Namespace, "base", base).destroy(comp),
Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
@@ -73,7 +72,6 @@ pub const Type = struct {
Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
- Id.Namespace => unreachable,
Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
Id.ArgTuple => unreachable,
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
@@ -89,7 +87,6 @@ pub const Type = struct {
Id.ComptimeInt,
Id.Undefined,
Id.Null,
- Id.Namespace,
Id.BoundFn,
Id.ArgTuple,
Id.Opaque,
@@ -123,7 +120,6 @@ pub const Type = struct {
Id.ComptimeInt,
Id.Undefined,
Id.Null,
- Id.Namespace,
Id.BoundFn,
Id.ArgTuple,
Id.Opaque,
@@ -1020,14 +1016,6 @@ pub const Type = struct {
}
};
- pub const Namespace = struct {
- base: Type,
-
- pub fn destroy(self: *Namespace, comp: *Compilation) void {
- comp.gpa().destroy(self);
- }
- };
-
pub const BoundFn = struct {
base: Type,
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 902c6e13c234fd15c43cd7434f7aee829afe8eef..9501e9d5e368625f30111f1c51831d81441afb01 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -21,7 +21,6 @@
#include "libc_installation.hpp"
struct AstNode;
-struct ImportTableEntry;
struct ZigFn;
struct Scope;
struct ScopeBlock;
@@ -317,7 +316,6 @@ struct ConstExprValue {
ConstUnionValue x_union;
ConstArrayValue x_array;
ConstPtrValue x_ptr;
- ImportTableEntry *x_import;
ConstArgTuple x_arg_tuple;
// populated if special == ConstValSpecialRuntime
@@ -369,10 +367,8 @@ struct Tld {
VisibMod visib_mod;
AstNode *source_node;
- ImportTableEntry *import;
+ ZigType *import;
Scope *parent_scope;
- // set this flag temporarily to detect infinite loops
- bool dep_loop_flag;
TldResolution resolution;
};
@@ -382,6 +378,7 @@ struct TldVar {
ZigVar *var;
Buf *extern_lib_name;
Buf *section_name;
+ bool analyzing_type; // flag to detect dependency loops
};
struct TldFn {
@@ -700,7 +697,7 @@ struct AstNodeUse {
AstNode *expr;
TldResolution resolution;
- ConstExprValue *value;
+ ConstExprValue *using_namespace_value;
};
struct AstNodeIfBoolExpr {
@@ -937,7 +934,7 @@ struct AstNode {
enum NodeType type;
size_t line;
size_t column;
- ImportTableEntry *owner;
+ ZigType *owner;
union {
AstNodeFnDef fn_def;
AstNodeFnProto fn_proto;
@@ -1075,12 +1072,32 @@ enum ResolveStatus {
ResolveStatusSizeKnown,
};
+struct ZigPackage {
+ Buf root_src_dir;
+ Buf root_src_path; // relative to root_src_dir
+ Buf pkg_path; // a.b.c.d which follows the package dependency chain from the root package
+
+ // reminder: hash tables must be initialized before use
+ HashMap package_table;
+};
+
+// Stuff that only applies to a struct which is the implicit root struct of a file
+struct RootStruct {
+ ZigPackage *package;
+ Buf *path; // relative to root_package->root_src_dir
+ ZigList *line_offsets;
+ Buf *source_code;
+ AstNode *c_import_node;
+ ZigLLVMDIFile *di_file;
+};
+
struct ZigTypeStruct {
AstNode *decl_node;
TypeStructField *fields;
ScopeDecls *decls_scope;
uint64_t size_bytes;
HashMap fields_by_name;
+ RootStruct *root_struct;
uint32_t src_field_count;
uint32_t gen_field_count;
@@ -1232,7 +1249,6 @@ enum ZigTypeId {
ZigTypeIdEnum,
ZigTypeIdUnion,
ZigTypeIdFn,
- ZigTypeIdNamespace,
ZigTypeIdBoundFn,
ZigTypeIdArgTuple,
ZigTypeIdOpaque,
@@ -1246,6 +1262,10 @@ enum OnePossibleValue {
OnePossibleValueYes,
};
+struct ZigTypeOpaque {
+ Buf *bare_name;
+};
+
struct ZigType {
ZigTypeId id;
Buf name;
@@ -1268,6 +1288,7 @@ struct ZigType {
ZigTypeBoundFn bound_fn;
ZigTypePromise promise;
ZigTypeVector vector;
+ ZigTypeOpaque opaque;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
@@ -1285,29 +1306,6 @@ struct ZigType {
bool gen_h_loop_flag;
};
-struct PackageTableEntry {
- Buf root_src_dir;
- Buf root_src_path; // relative to root_src_dir
-
- // reminder: hash tables must be initialized before use
- HashMap package_table;
-};
-
-struct ImportTableEntry {
- AstNode *root;
- Buf *path; // relative to root_package->root_src_dir
- PackageTableEntry *package;
- ZigLLVMDIFile *di_file;
- Buf *source_code;
- ZigList *line_offsets;
- ScopeDecls *decls_scope;
- AstNode *c_import_node;
- bool any_imports_failed;
- bool scanned;
-
- ZigList use_decls;
-};
-
enum FnAnalState {
FnAnalStateReady,
FnAnalStateProbing,
@@ -1670,7 +1668,7 @@ struct CodeGen {
LLVMValueRef return_err_fn;
// reminder: hash tables must be initialized before use
- HashMap import_table;
+ HashMap import_table;
HashMap builtin_fn_table;
HashMap primitive_type_table;
HashMap type_table;
@@ -1684,8 +1682,6 @@ struct CodeGen {
HashMap string_literals_table;
HashMap type_info_cache;
- ZigList import_queue;
- size_t import_queue_index;
ZigList resolve_queue;
size_t resolve_queue_index;
ZigList use_queue;
@@ -1699,14 +1695,14 @@ struct CodeGen {
ZigList errors_by_index;
size_t largest_err_name_len;
- PackageTableEntry *std_package;
- PackageTableEntry *panic_package;
- PackageTableEntry *test_runner_package;
- PackageTableEntry *compile_var_package;
- ImportTableEntry *compile_var_import;
- ImportTableEntry *root_import;
- ImportTableEntry *bootstrap_import;
- ImportTableEntry *test_runner_import;
+ ZigPackage *std_package;
+ ZigPackage *panic_package;
+ ZigPackage *test_runner_package;
+ ZigPackage *compile_var_package;
+ ZigType *compile_var_import;
+ ZigType *root_import;
+ ZigType *bootstrap_import;
+ ZigType *test_runner_import;
struct {
ZigType *entry_bool;
@@ -1731,7 +1727,6 @@ struct CodeGen {
ZigType *entry_unreachable;
ZigType *entry_type;
ZigType *entry_invalid;
- ZigType *entry_namespace;
ZigType *entry_block;
ZigType *entry_num_lit_int;
ZigType *entry_num_lit_float;
@@ -1851,7 +1846,7 @@ struct CodeGen {
Buf *root_out_name;
Buf *test_filter;
Buf *test_name_prefix;
- PackageTableEntry *root_package;
+ ZigPackage *root_package;
Buf *zig_lib_dir;
Buf *zig_std_dir;
@@ -1945,13 +1940,17 @@ struct ScopeDecls {
Scope base;
HashMap decl_table;
- bool safety_off;
+ ZigList use_decls;
AstNode *safety_set_node;
- bool fast_math_on;
AstNode *fast_math_set_node;
- ImportTableEntry *import;
+ ZigType *import;
// If this is a scope from a container, this is the type entry, otherwise null
ZigType *container_type;
+ Buf *bare_name;
+
+ bool safety_off;
+ bool fast_math_on;
+ bool any_imports_failed;
};
// This scope comes from a block expression in user code.
@@ -3463,7 +3462,8 @@ static const size_t err_union_err_index = 0;
static const size_t err_union_payload_index = 1;
// TODO call graph analysis to find out what this number needs to be for every function
-static const size_t stack_trace_ptr_count = 30;
+// MUST BE A POWER OF TWO.
+static const size_t stack_trace_ptr_count = 32;
// these belong to the async function
#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
@@ -3476,6 +3476,8 @@ static const size_t stack_trace_ptr_count = 30;
#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
#define RESULT_PTR_FIELD_NAME "result_ptr"
+#define NAMESPACE_SEP_CHAR '.'
+#define NAMESPACE_SEP_STR "."
enum FloatMode {
FloatModeStrict,
@@ -3507,7 +3509,7 @@ struct FnWalkTypes {
};
struct FnWalkVars {
- ImportTableEntry *import;
+ ZigType *import;
LLVMValueRef llvm_fn;
ZigFn *fn;
ZigVar *var;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 3ceda4193422c12826e766885730230c94a5e12e..366bb2963e1fd1395eecc16560c9c62f26836ee5 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -28,10 +28,14 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum
static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
-static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token,
- Buf *msg)
-{
- if (owner->c_import_node != nullptr) {
+static bool is_top_level_struct(ZigType *import) {
+ return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
+}
+
+static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, Token *token, Buf *msg) {
+ assert(is_top_level_struct(owner));
+ RootStruct *root_struct = owner->data.structure.root_struct;
+ if (root_struct->c_import_node != nullptr) {
// if this happens, then translate_c generated code that
// failed semantic analysis, which isn't supposed to happen
@@ -46,18 +50,20 @@ static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTa
return note;
}
- ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
- owner->source_code, owner->line_offsets, msg);
+ ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
+ root_struct->source_code, root_struct->line_offsets, msg);
err_msg_add_note(parent_msg, err);
return err;
}
-ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) {
- if (owner->c_import_node != nullptr) {
+ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
+ assert(is_top_level_struct(owner));
+ RootStruct *root_struct = owner->data.structure.root_struct;
+ if (root_struct->c_import_node != nullptr) {
// if this happens, then translate_c generated code that
// failed semantic analysis, which isn't supposed to happen
- ErrorMsg *err = add_node_error(g, owner->c_import_node,
+ ErrorMsg *err = add_node_error(g, root_struct->c_import_node,
buf_sprintf("compiler bug: @cImport generated invalid zig code"));
add_error_note_token(g, err, owner, token, msg);
@@ -65,8 +71,8 @@ ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf
g->errors.append(err);
return err;
}
- ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column,
- owner->source_code, owner->line_offsets, msg);
+ ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
+ root_struct->source_code, root_struct->line_offsets, msg);
g->errors.append(err);
return err;
@@ -114,13 +120,16 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope
dest->parent = parent;
}
-ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ImportTableEntry *import) {
+static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type,
+ ZigType *import, Buf *bare_name)
+{
assert(node == nullptr || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr);
ScopeDecls *scope = allocate(1);
init_scope(g, &scope->base, ScopeIdDecls, node, parent);
scope->decl_table.init(4);
scope->container_type = container_type;
scope->import = import;
+ scope->bare_name = bare_name;
return scope;
}
@@ -207,11 +216,11 @@ Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
return &scope->base;
}
-ImportTableEntry *get_scope_import(Scope *scope) {
+ZigType *get_scope_import(Scope *scope) {
while (scope) {
if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
- assert(decls_scope->import);
+ assert(is_top_level_struct(decls_scope->import));
return decls_scope->import;
}
scope = scope->parent;
@@ -219,9 +228,12 @@ ImportTableEntry *get_scope_import(Scope *scope) {
zig_unreachable();
}
-static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope) {
+static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope,
+ Buf *bare_name)
+{
ZigType *entry = new_type_table_entry(id);
- *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry, get_scope_import(parent_scope));
+ *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry,
+ get_scope_import(parent_scope), bare_name);
return entry;
}
@@ -261,7 +273,6 @@ AstNode *type_decl_node(ZigType *type_entry) {
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -323,7 +334,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -616,7 +626,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
if (child_type->zero_bits) {
entry->type_ref = LLVMInt1Type();
entry->di_type = g->builtin_types.entry_bool->di_type;
- } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
+ } else if (type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
assert(child_type->di_type);
// this is an optimization but also is necessary for calling C
// functions where all pointers are maybe pointers
@@ -1005,21 +1015,22 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
return entry;
}
-ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name) {
+ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name) {
ZigType *entry = new_type_table_entry(ZigTypeIdOpaque);
- buf_init_from_str(&entry->name, name);
+ buf_init_from_str(&entry->name, full_name);
- ImportTableEntry *import = scope ? get_scope_import(scope) : nullptr;
+ ZigType *import = scope ? get_scope_import(scope) : nullptr;
unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
entry->type_ref = LLVMInt8Type();
entry->di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
- ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
- import ? ZigLLVMFileToScope(import->di_file) : nullptr,
- import ? import->di_file : nullptr,
+ ZigLLVMTag_DW_structure_type(), full_name,
+ import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
+ import ? import->data.structure.root_struct->di_file : nullptr,
line);
entry->zero_bits = false;
+ entry->data.opaque.bare_name = bare_name;
return entry;
}
@@ -1288,11 +1299,32 @@ static ZigTypeId container_to_type(ContainerKind kind) {
zig_unreachable();
}
+// This is like get_partial_container_type except it's for the implicit root struct of files.
+ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
+ RootStruct *root_struct)
+{
+ ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
+ entry->data.structure.decls_scope = create_decls_scope(g, nullptr, nullptr, entry, entry, bare_name);
+ entry->data.structure.root_struct = root_struct;
+ entry->data.structure.layout = ContainerLayoutAuto;
+ entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
+
+ size_t line = 0; // root therefore first line
+ unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
+
+ entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+ dwarf_kind, full_name,
+ ZigLLVMFileToScope(root_struct->di_file), root_struct->di_file, (unsigned)(line + 1));
+
+ buf_init_from_str(&entry->name, full_name);
+ return entry;
+}
+
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
- AstNode *decl_node, const char *name, ContainerLayout layout)
+ AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout)
{
ZigTypeId type_id = container_to_type(kind);
- ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope);
+ ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope, bare_name);
switch (kind) {
case ContainerKindStruct:
@@ -1312,13 +1344,14 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
size_t line = decl_node ? decl_node->line : 0;
unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
- ImportTableEntry *import = get_scope_import(scope);
- entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
+ ZigType *import = get_scope_import(scope);
+ entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
- dwarf_kind, name,
- ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));
+ dwarf_kind, full_name,
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
+ import->data.structure.root_struct->di_file, (unsigned)(line + 1));
- buf_init_from_str(&entry->name, name);
+ buf_init_from_str(&entry->name, full_name);
return entry;
}
@@ -1459,7 +1492,6 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
case ZigTypeIdNull:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -1547,7 +1579,6 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdNull:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -1706,7 +1737,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
return g->builtin_types.entry_invalid;
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
@@ -1801,7 +1831,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdMetaType:
case ZigTypeIdUnreachable:
@@ -1880,7 +1909,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
if (!enum_type->data.enumeration.reported_infinite_err) {
enum_type->data.enumeration.is_invalid = true;
enum_type->data.enumeration.reported_infinite_err = true;
- add_node_error(g, decl_node, buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name)));
+ ErrorMsg *msg = add_node_error(g, decl_node,
+ buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name)));
+ emit_error_notes_for_ref_stack(g, msg);
}
return ErrorSemanticAnalyzeFail;
}
@@ -1895,7 +1926,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
ZigLLVMDIEnumerator **di_enumerators = allocate(field_count);
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
// set temporary flag
enum_type->data.enumeration.embedded_in_current = true;
@@ -1924,9 +1955,9 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
ZigLLVMDIType **di_root_members = nullptr;
size_t debug_member_count = 0;
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
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) {
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
tag_debug_size_in_bits,
tag_debug_align_in_bits,
di_enumerators, field_count,
@@ -2051,8 +2082,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
if (struct_type->data.structure.resolve_loop_flag) {
if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
- add_node_error(g, decl_node,
+ ErrorMsg *msg = add_node_error(g, decl_node,
buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
+ emit_error_notes_for_ref_stack(g, msg);
}
return ErrorSemanticAnalyzeFail;
}
@@ -2159,15 +2191,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
if (struct_type->zero_bits) {
struct_type->type_ref = LLVMVoidType();
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
uint64_t debug_size_in_bits = 0;
uint64_t debug_align_in_bits = 0;
ZigLLVMDIType **di_element_types = nullptr;
size_t debug_field_count = 0;
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
buf_ptr(&struct_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
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) {
ZigLLVMDIType **di_element_types = allocate(debug_field_count);
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
size_t debug_field_index = 0;
for (size_t i = 0; i < field_count; i += 1) {
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) {
}
di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
- import->di_file, (unsigned)(field_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
debug_offset_in_bits,
@@ -2247,9 +2279,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
buf_ptr(&struct_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
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) {
if (!union_type->data.unionation.reported_infinite_err) {
union_type->data.unionation.reported_infinite_err = true;
union_type->data.unionation.is_invalid = true;
- add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
+ ErrorMsg *msg = add_node_error(g, decl_node,
+ buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
+ emit_error_notes_for_ref_stack(g, msg);
}
return ErrorSemanticAnalyzeFail;
}
@@ -2298,7 +2332,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
uint64_t biggest_size_in_bits = 0;
Scope *scope = &union_type->data.unionation.decls_scope->base;
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
// set temporary flag
union_type->data.unionation.embedded_in_current = true;
@@ -2325,7 +2359,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),
- import->di_file, (unsigned)(field_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
store_size_in_bits,
abi_align_in_bits,
0,
@@ -2358,9 +2392,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
ZigLLVMDIType **di_root_members = nullptr;
size_t debug_member_count = 0;
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
buf_ptr(&union_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
0, di_root_members, (int)debug_member_count, 0, "");
@@ -2396,8 +2430,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
// create debug type for union
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
gen_field_count, 0, "");
@@ -2452,7 +2486,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
// create debug type for union
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
gen_field_count, 0, "");
@@ -2463,7 +2497,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "payload",
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
biggest_size_in_bits,
biggest_align_in_bits,
union_offset_in_bits,
@@ -2474,7 +2508,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "tag",
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
tag_debug_size_in_bits,
tag_debug_align_in_bits,
tag_offset_in_bits,
@@ -2487,9 +2521,9 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
buf_ptr(&union_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
debug_size_in_bits,
debug_align_in_bits,
0, nullptr, di_root_members, 2, 0, nullptr, "");
@@ -2507,8 +2541,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
return ErrorNone;
if (enum_type->data.enumeration.zero_bits_loop_flag) {
- add_node_error(g, enum_type->data.enumeration.decl_node,
+ ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node,
buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
+ emit_error_notes_for_ref_stack(g, msg);
enum_type->data.enumeration.is_invalid = true;
return ErrorSemanticAnalyzeFail;
}
@@ -2780,8 +2815,9 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
if (struct_type->data.structure.resolve_loop_flag) {
if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
- add_node_error(g, decl_node,
+ ErrorMsg *msg = add_node_error(g, decl_node,
buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
+ emit_error_notes_for_ref_stack(g, msg);
}
return ErrorSemanticAnalyzeFail;
}
@@ -3185,15 +3221,15 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
if (create_enum_type) {
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :
8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :
8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
// TODO get a more accurate debug scope
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
+ ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&tag_type->name),
+ import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
tag_type->di_type, "");
tag_type->di_type = tag_di_type;
@@ -3210,27 +3246,16 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorNone;
}
-static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
- if (!scope)
- return;
-
- if (scope->id == ScopeIdDecls) {
- get_fully_qualified_decl_name_internal(buf, scope->parent, sep);
-
- ScopeDecls *scope_decls = (ScopeDecls *)scope;
- if (scope_decls->container_type) {
- buf_append_buf(buf, &scope_decls->container_type->name);
- buf_append_char(buf, sep);
- }
- return;
- }
-
- get_fully_qualified_decl_name_internal(buf, scope->parent, sep);
-}
-
-static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) {
+static void get_fully_qualified_decl_name(Buf *buf, Tld *tld) {
buf_resize(buf, 0);
- get_fully_qualified_decl_name_internal(buf, tld->parent_scope, sep);
+
+ Scope *scope = tld->parent_scope;
+ while (scope->id != ScopeIdDecls) {
+ scope = scope->parent;
+ }
+ ScopeDecls *decls_scope = reinterpret_cast(scope);
+ buf_append_buf(buf, &decls_scope->container_type->name);
+ if (buf_len(buf) != 0) buf_append_char(buf, NAMESPACE_SEP_CHAR);
buf_append_buf(buf, tld->name);
}
@@ -3265,7 +3290,7 @@ static bool scope_is_root_decls(Scope *scope) {
while (scope) {
if (scope->id == ScopeIdDecls) {
ScopeDecls *scope_decls = (ScopeDecls *)scope;
- return (scope_decls->container_type == nullptr);
+ return is_top_level_struct(scope_decls->container_type);
}
scope = scope->parent;
}
@@ -3281,7 +3306,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
AstNode *fake_decl = allocate(1);
*fake_decl = *panic_fn->proto_node;
fake_decl->type = NodeTypeSymbol;
- fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name;
+ fake_decl->data.symbol_expr.symbol = tld_fn->base.name;
// call this for the side effects of casting to panic_fn_type
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
}
static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
- ImportTableEntry *import = tld_fn->base.import;
+ ZigType *import = tld_fn->base.import;
AstNode *source_node = tld_fn->base.source_node;
if (source_node->type == NodeTypeFnProto) {
AstNodeFnProto *fn_proto = &source_node->data.fn_proto;
@@ -3334,16 +3359,21 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
AstNode *fn_def_node = fn_proto->fn_def_node;
ZigFn *fn_table_entry = create_fn(g, source_node);
- get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
+ tld_fn->fn_entry = fn_table_entry;
+
+ bool is_extern = (fn_table_entry->body_node == nullptr);
+ if (fn_proto->is_export || is_extern) {
+ buf_init_from_buf(&fn_table_entry->symbol_name, tld_fn->base.name);
+ } else {
+ get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base);
+ }
if (fn_proto->is_export) {
bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC);
add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc);
}
- tld_fn->fn_entry = fn_table_entry;
-
- if (fn_table_entry->body_node) {
+ if (!is_extern) {
fn_table_entry->fndef_scope = create_fndef_scope(g,
fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry);
@@ -3382,12 +3412,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
}
if (scope_is_root_decls(tld_fn->base.parent_scope) &&
- (import == g->root_import || import->package == g->panic_package))
+ (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
{
- if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
+ if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) {
g->main_fn = fn_table_entry;
- } else if ((import->package == g->panic_package || g->have_pub_panic) &&
- buf_eql_str(&fn_table_entry->symbol_name, "panic"))
+ } else if ((import->data.structure.root_struct->package == g->panic_package || g->have_pub_panic) &&
+ buf_eql_str(tld_fn->base.name, "panic"))
{
g->panic_fn = fn_table_entry;
g->panic_tld_fn = tld_fn;
@@ -3396,7 +3426,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
} else if (source_node->type == NodeTypeTestDecl) {
ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto);
- get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
+ get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base);
tld_fn->fn_entry = fn_table_entry;
@@ -3473,8 +3503,8 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
if (!g->is_test_build)
return;
- ImportTableEntry *import = get_scope_import(&decls_scope->base);
- if (import->package != g->root_package)
+ ZigType *import = get_scope_import(&decls_scope->base);
+ if (import->data.structure.root_struct->package != g->root_package)
return;
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
}
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
- Tld *tld = g->compile_var_import->decls_scope->decl_table.get(name);
- resolve_top_level_decl(g, tld, false, tld->source_node);
+ Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name);
+ resolve_top_level_decl(g, tld, tld->source_node);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
tld_var->var->const_value = value;
@@ -3561,8 +3591,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeUse:
{
g->use_queue.append(node);
- ImportTableEntry *import = get_scope_import(&decls_scope->base);
- import->use_decls.append(node);
+ decls_scope->use_decls.append(node);
break;
}
case NodeTypeTestDecl:
@@ -3654,7 +3683,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
return g->builtin_types.entry_invalid;
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
- case ZigTypeIdNamespace:
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
case ZigTypeIdBool:
@@ -3763,8 +3791,16 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
ZigType *explicit_type = nullptr;
if (var_decl->type) {
- ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type);
- explicit_type = validate_var_type(g, var_decl->type, proposed_type);
+ if (tld_var->analyzing_type) {
+ ErrorMsg *msg = add_node_error(g, var_decl->type,
+ buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name)));
+ emit_error_notes_for_ref_stack(g, msg);
+ explicit_type = g->builtin_types.entry_invalid;
+ } else {
+ tld_var->analyzing_type = true;
+ ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type);
+ explicit_type = validate_var_type(g, var_decl->type, proposed_type);
+ }
}
assert(!is_export || !is_extern);
@@ -3847,17 +3883,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
g->global_vars.append(tld_var);
}
-void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node) {
+void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
if (tld->resolution != TldResolutionUnresolved)
return;
- if (tld->dep_loop_flag) {
- add_node_error(g, tld->source_node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name)));
- tld->resolution = TldResolutionInvalid;
- return;
- }
-
- tld->dep_loop_flag = true;
+ assert(tld->resolution != TldResolutionResolving);
+ tld->resolution = TldResolutionResolving;
g->tld_ref_source_node_stack.append(source_node);
switch (tld->id) {
@@ -3888,27 +3919,31 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
}
tld->resolution = TldResolutionOk;
- tld->dep_loop_flag = false;
g->tld_ref_source_node_stack.pop();
}
-Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
- // we must resolve all the use decls
- ImportTableEntry *import = get_scope_import(scope);
- for (size_t i = 0; i < import->use_decls.length; i += 1) {
- AstNode *use_decl_node = import->use_decls.at(i);
+Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
+ // resolve all the use decls
+ for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
+ AstNode *use_decl_node = decls_scope->use_decls.at(i);
if (use_decl_node->data.use.resolution == TldResolutionUnresolved) {
preview_use_decl(g, use_decl_node);
resolve_use_decl(g, use_decl_node);
}
}
+ auto entry = decls_scope->decl_table.maybe_get(name);
+ return (entry == nullptr) ? nullptr : entry->value;
+}
+
+Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
while (scope) {
if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
- auto entry = decls_scope->decl_table.maybe_get(name);
- if (entry)
- return entry->value;
+
+ Tld *result = find_container_decl(g, decls_scope, name);
+ if (result != nullptr)
+ return result;
}
scope = scope->parent;
}
@@ -3959,6 +3994,12 @@ ZigFn *scope_fn_entry(Scope *scope) {
return nullptr;
}
+ZigPackage *scope_package(Scope *scope) {
+ ZigType *import = get_scope_import(scope);
+ assert(is_top_level_struct(import));
+ return import->data.structure.root_struct->package;
+}
+
TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
assert(enum_type->id == ZigTypeIdEnum);
if (enum_type->data.enumeration.src_field_count == 0)
@@ -4039,7 +4080,6 @@ static bool is_container(ZigType *type_entry) {
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -4098,7 +4138,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdInvalid:
case ZigTypeIdArgTuple:
@@ -4131,10 +4170,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
}
bool type_is_nonnull_ptr(ZigType *type) {
- return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type);
+ return type_is_non_optional_pointer(type) && !ptr_allows_addr_zero(type);
}
-bool type_is_codegen_pointer(ZigType *type) {
+bool type_is_non_optional_pointer(ZigType *type) {
return get_codegen_ptr_type(type) == type;
}
@@ -4342,9 +4381,9 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
preview_use_decl(g, src_use_node);
}
- ConstExprValue *use_target_value = src_use_node->data.use.value;
+ ConstExprValue *use_target_value = src_use_node->data.use.using_namespace_value;
if (type_is_invalid(use_target_value->type)) {
- dst_use_node->owner->any_imports_failed = true;
+ get_container_scope(dst_use_node->owner)->any_imports_failed = true;
return;
}
@@ -4352,14 +4391,14 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
assert(use_target_value->special != ConstValSpecialRuntime);
- ImportTableEntry *target_import = use_target_value->data.x_import;
+ ZigType *target_import = use_target_value->data.x_type;
assert(target_import);
- if (target_import->any_imports_failed) {
- dst_use_node->owner->any_imports_failed = true;
+ if (get_container_scope(target_import)->any_imports_failed) {
+ get_container_scope(dst_use_node->owner)->any_imports_failed = true;
}
- auto it = target_import->decls_scope->decl_table.entry_iterator();
+ auto it = get_container_scope(target_import)->decl_table.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
@@ -4374,7 +4413,7 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
Buf *target_tld_name = entry->key;
- auto existing_entry = dst_use_node->owner->decls_scope->decl_table.put_unique(target_tld_name, target_tld);
+ auto existing_entry = get_container_scope(dst_use_node->owner)->decl_table.put_unique(target_tld_name, target_tld);
if (existing_entry) {
Tld *existing_decl = existing_entry->value;
if (existing_decl != target_tld) {
@@ -4387,8 +4426,8 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
}
}
- for (size_t i = 0; i < target_import->use_decls.length; i += 1) {
- AstNode *use_decl_node = target_import->use_decls.at(i);
+ for (size_t i = 0; i < get_container_scope(target_import)->use_decls.length; i += 1) {
+ AstNode *use_decl_node = get_container_scope(target_import)->use_decls.at(i);
if (use_decl_node->data.use.visib_mod != VisibModPrivate)
add_symbols_from_import(g, use_decl_node, dst_use_node);
}
@@ -4415,16 +4454,18 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
}
node->data.use.resolution = TldResolutionResolving;
- ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,
- node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
+ ConstExprValue *result = analyze_const_value(g, &get_container_scope(node->owner)->base,
+ node->data.use.expr, g->builtin_types.entry_type, nullptr);
if (type_is_invalid(result->type))
- node->owner->any_imports_failed = true;
+ get_container_scope(node->owner)->any_imports_failed = true;
- node->data.use.value = result;
+ node->data.use.using_namespace_value = result;
}
-ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *resolved_path, Buf *source_code) {
+ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code,
+ SourceKind source_kind)
+{
if (g->verbose_tokenize) {
fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(resolved_path));
fprintf(stderr, "----------------\n");
@@ -4452,87 +4493,102 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r
fprintf(stderr, "------\n");
}
- ImportTableEntry *import_entry = allocate(1);
- import_entry->package = package;
- import_entry->source_code = source_code;
- import_entry->line_offsets = tokenization.line_offsets;
- import_entry->path = resolved_path;
-
- import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
- assert(import_entry->root);
- if (g->verbose_ast) {
- ast_print(stderr, import_entry->root, 0);
- }
-
Buf *src_dirname = buf_alloc();
Buf *src_basename = buf_alloc();
os_path_split(resolved_path, src_dirname, src_basename);
- import_entry->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
+ Buf noextname = BUF_INIT;
+ os_path_extname(resolved_path, &noextname, nullptr);
+
+ Buf *pkg_root_src_dir = &package->root_src_dir;
+ Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1);
+
+ assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir));
+
+ Buf namespace_name = BUF_INIT;
+ buf_init_from_buf(&namespace_name, &package->pkg_path);
+ if (source_kind == SourceKindNonRoot) {
+ if (buf_len(&namespace_name) != 0) buf_append_char(&namespace_name, NAMESPACE_SEP_CHAR);
+ buf_append_mem(&namespace_name, buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1,
+ buf_len(&noextname) - (buf_len(&resolved_root_src_dir) + 1));
+ buf_replace(&namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR);
+ }
+ Buf *bare_name = buf_alloc();
+ os_path_extname(src_basename, bare_name, nullptr);
+
+ RootStruct *root_struct = allocate(1);
+ root_struct->package = package;
+ root_struct->source_code = source_code;
+ root_struct->line_offsets = tokenization.line_offsets;
+ root_struct->path = resolved_path;
+ root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
+ ZigType *import_entry = get_root_container_type(g, buf_ptr(&namespace_name), bare_name, root_struct);
+ if (source_kind == SourceKindRoot) {
+ assert(g->root_import == nullptr);
+ g->root_import = import_entry;
+ }
g->import_table.put(resolved_path, import_entry);
- g->import_queue.append(import_entry);
- import_entry->decls_scope = create_decls_scope(g, import_entry->root, nullptr, nullptr, import_entry);
+ AstNode *root_node = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
+ assert(root_node != nullptr);
+ assert(root_node->type == NodeTypeContainerDecl);
+ import_entry->data.structure.decl_node = root_node;
+ import_entry->data.structure.decls_scope->base.source_node = root_node;
+ if (g->verbose_ast) {
+ ast_print(stderr, root_node, 0);
+ }
+ if (source_kind == SourceKindRoot || package == g->panic_package) {
+ // Look for panic and main
+ for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
+ AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
- assert(import_entry->root->type == NodeTypeContainerDecl);
- for (size_t decl_i = 0; decl_i < import_entry->root->data.container_decl.decls.length; decl_i += 1) {
- AstNode *top_level_decl = import_entry->root->data.container_decl.decls.at(decl_i);
+ if (top_level_decl->type == NodeTypeFnDef) {
+ AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
+ assert(proto_node->type == NodeTypeFnProto);
+ Buf *proto_name = proto_node->data.fn_proto.name;
- if (top_level_decl->type == NodeTypeFnDef) {
- AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
- assert(proto_node->type == NodeTypeFnProto);
- Buf *proto_name = proto_node->data.fn_proto.name;
-
- bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
- bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified ||
- proto_node->data.fn_proto.cc == CallingConventionCold);
-
- if (is_pub && ok_cc) {
- if (buf_eql_str(proto_name, "main")) {
- g->have_pub_main = true;
- g->subsystem = TargetSubsystemConsole;
- } else if (buf_eql_str(proto_name, "panic")) {
- g->have_pub_panic = true;
+ bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
+ if (is_pub) {
+ if (buf_eql_str(proto_name, "main")) {
+ g->have_pub_main = true;
+ g->subsystem = TargetSubsystemConsole;
+ } else if (buf_eql_str(proto_name, "panic")) {
+ g->have_pub_panic = true;
+ }
}
}
}
}
+ for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) {
+ AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i);
+ scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl);
+ }
+
+ TldContainer *tld_container = allocate(1);
+ init_tld(&tld_container->base, TldIdContainer, &namespace_name, VisibModPub, root_node, nullptr);
+ tld_container->type_entry = import_entry;
+ tld_container->decls_scope = import_entry->data.structure.decls_scope;
+ g->resolve_queue.append(&tld_container->base);
+
return import_entry;
}
-void scan_import(CodeGen *g, ImportTableEntry *import) {
- if (!import->scanned) {
- import->scanned = true;
- scan_decls(g, import->decls_scope, import->root);
- }
-}
-
void semantic_analyze(CodeGen *g) {
- for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) {
- ImportTableEntry *import = g->import_queue.at(g->import_queue_index);
- scan_import(g, import);
- }
-
- for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
- AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
- preview_use_decl(g, use_decl_node);
- }
-
- for (size_t i = 0; i < g->use_queue.length; i += 1) {
- AstNode *use_decl_node = g->use_queue.at(i);
- resolve_use_decl(g, use_decl_node);
- }
-
while (g->resolve_queue_index < g->resolve_queue.length ||
- g->fn_defs_index < g->fn_defs.length)
+ g->fn_defs_index < g->fn_defs.length ||
+ g->use_queue_index < g->use_queue.length)
{
+ for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
+ AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
+ preview_use_decl(g, use_decl_node);
+ resolve_use_decl(g, use_decl_node);
+ }
for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
- bool pointer_only = false;
AstNode *source_node = nullptr;
- resolve_top_level_decl(g, tld, pointer_only, source_node);
+ resolve_top_level_decl(g, tld, source_node);
}
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) {
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -4637,7 +4692,7 @@ bool handle_is_ptr(ZigType *type_entry) {
return type_has_bits(type_entry->data.error_union.payload_type);
case ZigTypeIdOptional:
return type_has_bits(type_entry->data.maybe.child_type) &&
- !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&
+ !type_is_non_optional_pointer(type_entry->data.maybe.child_type) &&
type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
case ZigTypeIdUnion:
assert(type_entry->data.unionation.zero_bits_known);
@@ -4880,8 +4935,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
return 3415065496;
case ZigTypeIdErrorSet:
return hash_const_val_error_set(const_val);
- case ZigTypeIdNamespace:
- return hash_ptr(const_val->data.x_import);
case ZigTypeIdVector:
// TODO better hashing algorithm
return 3647867726;
@@ -4943,7 +4996,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdFn:
case ZigTypeIdOpaque:
@@ -5013,7 +5065,6 @@ static bool return_type_is_cacheable(ZigType *return_type) {
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdFn:
case ZigTypeIdOpaque:
@@ -5143,7 +5194,6 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdMetaType:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOptional:
@@ -5209,7 +5259,6 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdMetaType:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
return ReqCompTimeYes;
@@ -5797,8 +5846,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
}
case ZigTypeIdErrorUnion:
zig_panic("TODO");
- case ZigTypeIdNamespace:
- return a->data.x_import == b->data.x_import;
case ZigTypeIdArgTuple:
return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
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) {
}
return;
}
- case ZigTypeIdNamespace:
- {
- ImportTableEntry *import = const_val->data.x_import;
- if (import->c_import_node) {
- buf_appendf(buf, "(namespace from C import)");
- } else {
- buf_appendf(buf, "(namespace: %s)", buf_ptr(import->path));
- }
- return;
- }
case ZigTypeIdBoundFn:
{
ZigFn *fn_entry = const_val->data.x_bound_fn.fn;
@@ -6203,7 +6240,6 @@ uint32_t type_id_hash(TypeId x) {
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -6252,7 +6288,6 @@ bool type_id_eql(TypeId a, TypeId b) {
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -6419,7 +6454,6 @@ static const ZigTypeId all_type_ids[] = {
ZigTypeIdEnum,
ZigTypeIdUnion,
ZigTypeIdFn,
- ZigTypeIdNamespace,
ZigTypeIdBoundFn,
ZigTypeIdArgTuple,
ZigTypeIdOpaque,
@@ -6480,18 +6514,16 @@ size_t type_id_index(ZigType *entry) {
return 17;
case ZigTypeIdFn:
return 18;
- case ZigTypeIdNamespace:
+ case ZigTypeIdBoundFn:
return 19;
- case ZigTypeIdBoundFn:
+ case ZigTypeIdArgTuple:
return 20;
- case ZigTypeIdArgTuple:
+ case ZigTypeIdOpaque:
return 21;
- case ZigTypeIdOpaque:
+ case ZigTypeIdPromise:
return 22;
- case ZigTypeIdPromise:
+ case ZigTypeIdVector:
return 23;
- case ZigTypeIdVector:
- return 24;
}
zig_unreachable();
}
@@ -6538,8 +6570,6 @@ const char *type_id_name(ZigTypeId id) {
return "Union";
case ZigTypeIdFn:
return "Fn";
- case ZigTypeIdNamespace:
- return "Namespace";
case ZigTypeIdBoundFn:
return "BoundFn";
case ZigTypeIdArgTuple:
@@ -6619,8 +6649,8 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) {
}
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
- Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
- resolve_top_level_decl(codegen, tld, false, nullptr);
+ Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
+ resolve_top_level_decl(codegen, tld, nullptr);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
ConstExprValue *var_value = tld_var->var->const_value;
@@ -6812,3 +6842,34 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) {
}
return false;
}
+
+void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg) {
+ size_t i = g->tld_ref_source_node_stack.length;
+ for (;;) {
+ if (i == 0)
+ break;
+ i -= 1;
+ AstNode *source_node = g->tld_ref_source_node_stack.at(i);
+ if (source_node) {
+ msg = add_error_note(g, msg, source_node, buf_sprintf("referenced here"));
+ }
+ }
+}
+
+Buf *type_bare_name(ZigType *type_entry) {
+ if (is_slice(type_entry)) {
+ return &type_entry->name;
+ } else if (is_container(type_entry)) {
+ return get_container_scope(type_entry)->bare_name;
+ } else if (type_entry->id == ZigTypeIdOpaque) {
+ return type_entry->data.opaque.bare_name;
+ } else {
+ return &type_entry->name;
+ }
+}
+
+// TODO this will have to be more clever, probably using the full name
+// and replacing '.' with '_' or something like that
+Buf *type_h_name(ZigType *t) {
+ return type_bare_name(t);
+}
diff --git a/src/analyze.hpp b/src/analyze.hpp
index e8838ae57eb425dd80f9228d22608cea64655ae3..aa94f0c2c5ce70cad938a61783bd721b8cef4fba 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -12,8 +12,9 @@
void semantic_analyze(CodeGen *g);
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
-ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg);
+ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
+void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
ZigType *new_type_table_entry(ZigTypeId id);
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
ZigType *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);
ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
- AstNode *decl_node, const char *name, ContainerLayout layout);
+ AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
+ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
+ RootStruct *root_struct);
ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
-ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);
+ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
ZigType *field_types[], size_t field_count);
ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
@@ -46,13 +49,19 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
bool ptr_allows_addr_zero(ZigType *ptr_type);
bool type_is_nonnull_ptr(ZigType *type);
-ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
-
+enum SourceKind {
+ SourceKindRoot,
+ SourceKindPkgMain,
+ SourceKindNonRoot,
+};
+ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Buf *source_code,
+ SourceKind source_kind);
ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
-void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
-bool type_is_codegen_pointer(ZigType *type);
+Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name);
+void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node);
+bool type_is_non_optional_pointer(ZigType *type);
ZigType *get_src_ptr_type(ZigType *type);
ZigType *get_codegen_ptr_type(ZigType *type);
@@ -77,11 +86,11 @@ bool is_array_ref(ZigType *type_entry);
bool is_container_ref(ZigType *type_entry);
bool is_valid_vector_elem_type(ZigType *elem_type);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
-void scan_import(CodeGen *g, ImportTableEntry *import);
void preview_use_decl(CodeGen *g, AstNode *node);
void resolve_use_decl(CodeGen *g, AstNode *node);
ZigFn *scope_fn_entry(Scope *scope);
-ImportTableEntry *get_scope_import(Scope *scope);
+ZigPackage *scope_package(Scope *scope);
+ZigType *get_scope_import(Scope *scope);
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
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);
ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
-ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ImportTableEntry *import);
Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
@@ -186,7 +194,7 @@ LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);
ZigType *get_align_amt_type(CodeGen *g);
-PackageTableEntry *new_anonymous_package(void);
+ZigPackage *new_anonymous_package(void);
Buf *const_value_to_buffer(ConstExprValue *const_val);
void 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
ConstExprValue *const_val, ZigType *wanted_type);
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
+Buf *type_bare_name(ZigType *t);
+Buf *type_h_name(ZigType *t);
#endif
diff --git a/src/buffer.hpp b/src/buffer.hpp
index e286f7dc637d13627ad9a70be1512d4acde02136..789abea3e9ee0a441886bd410d64f184287f2751 100644
--- a/src/buffer.hpp
+++ b/src/buffer.hpp
@@ -59,7 +59,7 @@ static inline void buf_deinit(Buf *buf) {
static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) {
assert(len != SIZE_MAX);
buf->list.resize(len + 1);
- safe_memcpy(buf_ptr(buf), ptr, len);
+ memcpy(buf_ptr(buf), ptr, len);
buf->list.at(buf_len(buf)) = 0;
}
@@ -98,7 +98,7 @@ static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) {
assert(end <= buf_len(in_buf));
Buf *out_buf = allocate(1);
out_buf->list.resize(end - start + 1);
- safe_memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start);
+ memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start);
out_buf->list.at(buf_len(out_buf)) = 0;
return out_buf;
}
@@ -108,7 +108,7 @@ static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) {
assert(mem_len != SIZE_MAX);
size_t old_len = buf_len(buf);
buf_resize(buf, old_len + mem_len);
- safe_memcpy(buf_ptr(buf) + old_len, mem, mem_len);
+ memcpy(buf_ptr(buf) + old_len, mem, mem_len);
buf->list.at(buf_len(buf)) = 0;
}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ee63318eb8c00e03956b81033b63361245f637b3..7b256982baf7a70dc4186bcc243a6619cc0642f0 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -48,16 +48,17 @@ static void init_darwin_native(CodeGen *g) {
}
}
-static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {
- PackageTableEntry *entry = allocate(1);
+static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
+ ZigPackage *entry = allocate(1);
entry->package_table.init(4);
buf_init_from_str(&entry->root_src_dir, root_src_dir);
buf_init_from_str(&entry->root_src_path, root_src_path);
+ buf_init_from_str(&entry->pkg_path, pkg_path);
return entry;
}
-PackageTableEntry *new_anonymous_package(void) {
- return new_package("", "");
+ZigPackage *new_anonymous_package() {
+ return new_package("", "", "");
}
static const char *symbols_that_llvm_depends_on[] = {
@@ -87,8 +88,8 @@ static const char *symbols_that_llvm_depends_on[] = {
// TODO probably all of compiler-rt needs to go here
};
-CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
- Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)
+CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
+ OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc)
{
CodeGen *g = allocate(1);
@@ -132,20 +133,39 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
}
if (root_src_path) {
- Buf *src_basename = buf_alloc();
- Buf *src_dir = buf_alloc();
- os_path_split(root_src_path, src_dir, src_basename);
+ Buf *root_pkg_path;
+ Buf *rel_root_src_path;
+ if (main_pkg_path == nullptr) {
+ Buf *src_basename = buf_alloc();
+ Buf *src_dir = buf_alloc();
+ os_path_split(root_src_path, src_dir, src_basename);
- if (buf_len(src_basename) == 0) {
- fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
- exit(1);
+ if (buf_len(src_basename) == 0) {
+ fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
+ exit(1);
+ }
+ root_pkg_path = src_dir;
+ rel_root_src_path = src_basename;
+ } else {
+ Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
+ Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
+
+ if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
+ fprintf(stderr, "Root source path '%s' outside main package path '%s'",
+ buf_ptr(root_src_path), buf_ptr(main_pkg_path));
+ exit(1);
+ }
+ root_pkg_path = main_pkg_path;
+ rel_root_src_path = buf_create_from_mem(
+ buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
+ buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
}
- g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));
- g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");
+ g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
+ g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
} else {
- g->root_package = new_package(".", "");
+ g->root_package = new_package(".", "", "");
}
g->zig_std_special_dir = buf_alloc();
@@ -621,7 +641,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
if (scope->di_scope)
return scope->di_scope;
- ImportTableEntry *import = get_scope_import(scope);
+ ZigType *import = get_scope_import(scope);
switch (scope->id) {
case ScopeIdCImport:
zig_unreachable();
@@ -644,7 +664,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
assert(fn_di_scope != nullptr);
ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
- import->di_file, line_number,
+ import->data.structure.root_struct->di_file, line_number,
fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
is_definition, scope_line, flags, is_optimized, nullptr);
@@ -658,7 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
assert(decls_scope->container_type);
scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
} else {
- scope->di_scope = ZigLLVMFileToScope(import->di_file);
+ scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file);
}
return scope->di_scope;
case ScopeIdBlock:
@@ -668,7 +688,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
assert(scope->parent);
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
get_di_scope(g, scope->parent),
- import->di_file,
+ import->data.structure.root_struct->di_file,
(unsigned)scope->source_node->line + 1,
(unsigned)scope->source_node->column + 1);
scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
@@ -1236,7 +1256,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
- // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
+ // stack_trace.instruction_addresses[stack_trace.index & (stack_trace.instruction_addresses.len - 1)] = return_address;
LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
@@ -1254,9 +1274,10 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
- LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, len_value, "");
+ LLVMValueRef len_val_minus_one = LLVMBuildSub(g->builder, len_value, LLVMConstInt(usize_type_ref, 1, false), "");
+ LLVMValueRef masked_val = LLVMBuildAnd(g->builder, index_val, len_val_minus_one, "");
LLVMValueRef address_indices[] = {
- modded_val,
+ masked_val,
};
LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
@@ -2196,7 +2217,7 @@ var_ok:
if (dest_ty != nullptr && var->decl_node) {
// arg index + 1 because the 0 index is return value
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
- buf_ptr(&var->name), fn_walk->data.vars.import->di_file,
+ buf_ptr(&var->name), fn_walk->data.vars.import->data.structure.root_struct->di_file,
(unsigned)(var->decl_node->line + 1),
dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
}
@@ -3938,7 +3959,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
if (child_type->zero_bits) {
return maybe_handle;
} else {
- bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ bool is_scalar = type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
if (is_scalar) {
return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
} else {
@@ -3978,7 +3999,7 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
if (child_type->zero_bits) {
return nullptr;
} else {
- bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ bool is_scalar = type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
if (is_scalar) {
return maybe_ptr;
} else {
@@ -4549,7 +4570,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
return tmp_struct_ptr;
} else if (array_type->id == ZigTypeIdPointer) {
- assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
+ assert(array_type->data.pointer.ptr_len != PtrLenSingle);
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
@@ -4640,7 +4661,8 @@ static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executabl
IrInstructionReturnAddress *instruction)
{
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
- return LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
+ LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
+ return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
}
static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
@@ -4661,7 +4683,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
IrInstructionFrameAddress *instruction)
{
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
- return LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
+ LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
+ return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
}
static LLVMValueRef get_handle_fn_val(CodeGen *g) {
@@ -4839,7 +4862,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
}
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
+ if (type_is_non_optional_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
return payload_val;
}
@@ -5800,7 +5823,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case ZigTypeIdNull:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdVoid:
@@ -6077,9 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
case ZigTypeIdOptional:
{
ZigType *child_type = type_entry->data.maybe.child_type;
- if (child_type->zero_bits) {
+ if (!type_has_bits(child_type)) {
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
- } else if (type_is_codegen_pointer(child_type)) {
+ } else if (get_codegen_ptr_type(type_entry) != nullptr) {
return gen_const_val_ptr(g, const_val, name);
} else if (child_type->id == ZigTypeIdErrorSet) {
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
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -6506,12 +6527,12 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
assert(var->gen_is_const);
assert(type_entry);
- ImportTableEntry *import = get_scope_import(var->parent_scope);
+ ZigType *import = get_scope_import(var->parent_scope);
assert(import);
bool is_local_to_unit = true;
ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
- buf_ptr(&var->name), import->di_file,
+ buf_ptr(&var->name), import->data.structure.root_struct->di_file,
(unsigned)(var->decl_node->line + 1),
type_entry->di_type, is_local_to_unit);
@@ -6767,7 +6788,7 @@ static void do_code_gen(CodeGen *g) {
*slot = build_alloca(g, slot_type, "", alignment_bytes);
}
- ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
+ ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;
@@ -6799,7 +6820,7 @@ static void do_code_gen(CodeGen *g) {
var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
- buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
+ buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1),
var->var_type->di_type, !g->strip_debug_symbols, 0);
} else if (is_c_abi) {
@@ -6823,7 +6844,7 @@ static void do_code_gen(CodeGen *g) {
}
if (var->decl_node) {
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
- buf_ptr(&var->name), import->di_file,
+ buf_ptr(&var->name), import->data.structure.root_struct->di_file,
(unsigned)(var->decl_node->line + 1),
gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
}
@@ -6971,12 +6992,6 @@ static void define_builtin_types(CodeGen *g) {
entry->zero_bits = true;
g->builtin_types.entry_invalid = entry;
}
- {
- ZigType *entry = new_type_table_entry(ZigTypeIdNamespace);
- buf_init_from_str(&entry->name, "(namespace)");
- entry->zero_bits = true;
- g->builtin_types.entry_namespace = entry;
- }
{
ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
buf_init_from_str(&entry->name, "comptime_float");
@@ -7130,7 +7145,8 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
{
- g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");
+ g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void",
+ buf_create_from_str("c_void"));
g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);
}
@@ -7470,7 +7486,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" Enum: Enum,\n"
" Union: Union,\n"
" Fn: Fn,\n"
- " Namespace: void,\n"
" BoundFn: Fn,\n"
" ArgTuple: void,\n"
" Opaque: void,\n"
@@ -7479,18 +7494,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
"\n\n"
" pub const Int = struct {\n"
" is_signed: bool,\n"
- " bits: u8,\n"
+ " bits: comptime_int,\n"
" };\n"
"\n"
" pub const Float = struct {\n"
- " bits: u8,\n"
+ " bits: comptime_int,\n"
" };\n"
"\n"
" pub const Pointer = struct {\n"
" size: Size,\n"
" is_const: bool,\n"
" is_volatile: bool,\n"
- " alignment: u32,\n"
+ " alignment: comptime_int,\n"
" child: type,\n"
"\n"
" pub const Size = enum {\n"
@@ -7502,7 +7517,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" };\n"
"\n"
" pub const Array = struct {\n"
- " len: usize,\n"
+ " len: comptime_int,\n"
" child: type,\n"
" };\n"
"\n"
@@ -7514,7 +7529,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
"\n"
" pub const StructField = struct {\n"
" name: []const u8,\n"
- " offset: ?usize,\n"
+ " offset: ?comptime_int,\n"
" field_type: type,\n"
" };\n"
"\n"
@@ -7535,7 +7550,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
"\n"
" pub const Error = struct {\n"
" name: []const u8,\n"
- " value: usize,\n"
+ " value: comptime_int,\n"
" };\n"
"\n"
" pub const ErrorSet = struct {\n"
@@ -7544,7 +7559,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
"\n"
" pub const EnumField = struct {\n"
" name: []const u8,\n"
- " value: usize,\n"
+ " value: comptime_int,\n"
" };\n"
"\n"
" pub const Enum = struct {\n"
@@ -7596,7 +7611,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" };\n"
"\n"
" pub const Vector = struct {\n"
- " len: u32,\n"
+ " len: comptime_int,\n"
" child: type,\n"
" };\n"
"\n"
@@ -7751,12 +7766,12 @@ static Error define_builtin_compile_vars(CodeGen *g) {
assert(g->root_package);
assert(g->std_package);
- g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);
+ g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename, "builtin");
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
g->std_package->package_table.put(buf_create_from_str("std"), g->std_package);
- g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);
- scan_import(g, g->compile_var_import);
+ g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents,
+ SourceKindPkgMain);
return ErrorNone;
}
@@ -7948,17 +7963,20 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
Buf *src_dirname = buf_alloc();
os_path_split(full_path, src_dirname, src_basename);
- ImportTableEntry *import = allocate(1);
- import->source_code = nullptr;
- import->path = full_path;
+ Buf noextname = BUF_INIT;
+ os_path_extname(src_basename, &noextname, nullptr);
+
+ detect_libc(g);
+
+ init(g);
+
+ RootStruct *root_struct = allocate(1);
+ root_struct->source_code = nullptr;
+ root_struct->path = full_path;
+ root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
+
+ ZigType *import = get_root_container_type(g, buf_ptr(&noextname), &noextname, root_struct);
g->root_import = import;
- import->decls_scope = create_decls_scope(g, nullptr, nullptr, nullptr, import);
-
- detect_libc(g);
-
- init(g);
-
- import->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
ZigList errors = {0};
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) {
}
}
-static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {
+static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *basename) {
Buf *code_basename = buf_create_from_str(basename);
Buf path_to_code_src = BUF_INIT;
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
zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
}
- return add_source_file(g, package, resolved_path, import_code);
+ return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain);
}
-static PackageTableEntry *create_bootstrap_pkg(CodeGen *g, PackageTableEntry *pkg_with_main) {
- PackageTableEntry *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig");
+static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) {
+ ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special");
package->package_table.put(buf_create_from_str("@root"), pkg_with_main);
return package;
}
-static PackageTableEntry *create_test_runner_pkg(CodeGen *g) {
- return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig");
+static ZigPackage *create_test_runner_pkg(CodeGen *g) {
+ return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
}
-static PackageTableEntry *create_panic_pkg(CodeGen *g) {
- return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig");
+static ZigPackage *create_panic_pkg(CodeGen *g) {
+ return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
}
static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
@@ -8089,24 +8107,24 @@ static void gen_root_source(CodeGen *g) {
exit(1);
}
- g->root_import = add_source_file(g, g->root_package, resolved_path, source_code);
+ ZigType *root_import_alias = add_source_file(g, g->root_package, resolved_path, source_code, SourceKindRoot);
+ assert(root_import_alias == g->root_import);
assert(g->root_out_name);
assert(g->out_type != OutTypeUnknown);
{
// Zig has lazy top level definitions. Here we semantically analyze the panic function.
- ImportTableEntry *import_with_panic;
+ ZigType *import_with_panic;
if (g->have_pub_panic) {
import_with_panic = g->root_import;
} else {
g->panic_package = create_panic_pkg(g);
import_with_panic = add_special_code(g, g->panic_package, "panic.zig");
}
- scan_import(g, import_with_panic);
- Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic"));
+ Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic"));
assert(panic_tld != nullptr);
- resolve_top_level_decl(g, panic_tld, false, nullptr);
+ resolve_top_level_decl(g, panic_tld, nullptr);
}
@@ -8358,7 +8376,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdErrorUnion:
@@ -8496,7 +8513,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
if (child_type->zero_bits) {
buf_init_from_str(out_buf, "bool");
return;
- } else if (type_is_codegen_pointer(child_type)) {
+ } else if (type_is_non_optional_pointer(child_type)) {
return get_c_type(g, gen_h, child_type, out_buf);
} else {
zig_unreachable();
@@ -8506,19 +8523,19 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
case ZigTypeIdOpaque:
{
buf_init_from_str(out_buf, "struct ");
- buf_append_buf(out_buf, &type_entry->name);
+ buf_append_buf(out_buf, type_h_name(type_entry));
return;
}
case ZigTypeIdUnion:
{
buf_init_from_str(out_buf, "union ");
- buf_append_buf(out_buf, &type_entry->name);
+ buf_append_buf(out_buf, type_h_name(type_entry));
return;
}
case ZigTypeIdEnum:
{
buf_init_from_str(out_buf, "enum ");
- buf_append_buf(out_buf, &type_entry->name);
+ buf_append_buf(out_buf, type_h_name(type_entry));
return;
}
case ZigTypeIdArray:
@@ -8541,7 +8558,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
case ZigTypeIdInvalid:
case ZigTypeIdMetaType:
case ZigTypeIdBoundFn:
- case ZigTypeIdNamespace:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
@@ -8614,10 +8630,17 @@ static void gen_h_file(CodeGen *g) {
Buf return_type_c = BUF_INIT;
get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c);
+ Buf *symbol_name;
+ if (fn_table_entry->export_list.length == 0) {
+ symbol_name = &fn_table_entry->symbol_name;
+ } else {
+ FnExport *fn_export = &fn_table_entry->export_list.items[0];
+ symbol_name = &fn_export->name;
+ }
buf_appendf(&h_buf, "%s %s %s(",
buf_ptr(export_macro),
buf_ptr(&return_type_c),
- buf_ptr(&fn_table_entry->symbol_name));
+ buf_ptr(symbol_name));
Buf param_type_c = BUF_INIT;
if (fn_type_id->param_count > 0) {
@@ -8693,7 +8716,6 @@ static void gen_h_file(CodeGen *g) {
case ZigTypeIdNull:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOptional:
@@ -8703,7 +8725,7 @@ static void gen_h_file(CodeGen *g) {
zig_unreachable();
case ZigTypeIdEnum:
if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
- fprintf(out_h, "enum %s {\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));
for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
Buf *value_buf = buf_alloc();
@@ -8716,12 +8738,12 @@ static void gen_h_file(CodeGen *g) {
}
fprintf(out_h, "};\n\n");
} else {
- fprintf(out_h, "enum %s;\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "enum %s;\n", buf_ptr(type_h_name(type_entry)));
}
break;
case ZigTypeIdStruct:
if (type_entry->data.structure.layout == ContainerLayoutExtern) {
- fprintf(out_h, "struct %s {\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "struct %s {\n", buf_ptr(type_h_name(type_entry)));
for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
TypeStructField *struct_field = &type_entry->data.structure.fields[field_i];
@@ -8739,12 +8761,12 @@ static void gen_h_file(CodeGen *g) {
}
fprintf(out_h, "};\n\n");
} else {
- fprintf(out_h, "struct %s;\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "struct %s;\n", buf_ptr(type_h_name(type_entry)));
}
break;
case ZigTypeIdUnion:
if (type_entry->data.unionation.layout == ContainerLayoutExtern) {
- fprintf(out_h, "union %s {\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "union %s {\n", buf_ptr(type_h_name(type_entry)));
for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
@@ -8754,11 +8776,11 @@ static void gen_h_file(CodeGen *g) {
}
fprintf(out_h, "};\n\n");
} else {
- fprintf(out_h, "union %s;\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "union %s;\n", buf_ptr(type_h_name(type_entry)));
}
break;
case ZigTypeIdOpaque:
- fprintf(out_h, "struct %s;\n\n", buf_ptr(&type_entry->name));
+ fprintf(out_h, "struct %s;\n\n", buf_ptr(type_h_name(type_entry)));
break;
}
}
@@ -8792,7 +8814,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
g->timing_events.append({os_get_time(), name});
}
-static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
+static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) {
if (buf_len(&pkg->root_src_path) == 0)
return;
@@ -9046,9 +9068,11 @@ void codegen_build_and_link(CodeGen *g) {
codegen_add_time_event(g, "Done");
}
-PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
+ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
+ const char *pkg_path)
+{
init(g);
- PackageTableEntry *pkg = new_package(root_src_dir, root_src_path);
+ ZigPackage *pkg = new_package(root_src_dir, root_src_path, pkg_path);
if (g->std_package != nullptr) {
assert(g->compile_var_package != nullptr);
pkg->package_table.put(buf_create_from_str("std"), g->std_package);
diff --git a/src/codegen.hpp b/src/codegen.hpp
index 4f62cc4cbc7103076a7b8ea9f8549927333899cd..91598fa7bebc88f89ddc84f68fc612cd5cfd26cd 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -15,8 +15,8 @@
#include
-CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
- Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
+CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
+ OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
void 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);
void codegen_link(CodeGen *g);
void codegen_build_and_link(CodeGen *g);
-PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);
+ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
+ const char *pkg_path);
void codegen_add_assembly(CodeGen *g, Buf *path);
void codegen_add_object(CodeGen *g, Buf *object_path);
diff --git a/src/compiler.cpp b/src/compiler.cpp
index 0d4dff5d506d7523a3a7ac53a01938c90a882e98..8c2f9cdf608766639316a300de1624011dccc46c 100644
--- a/src/compiler.cpp
+++ b/src/compiler.cpp
@@ -78,8 +78,8 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
Buf std_buf = BUF_INIT;
buf_init_from_str(&std_buf, "std");
- Buf index_zig_buf = BUF_INIT;
- buf_init_from_str(&index_zig_buf, "index.zig");
+ Buf std_zig_buf = BUF_INIT;
+ buf_init_from_str(&std_zig_buf, "std.zig");
Buf test_lib_dir = BUF_INIT;
Buf test_zig_dir = BUF_INIT;
@@ -89,7 +89,7 @@ static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
os_path_join(test_path, &lib_buf, &test_lib_dir);
os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir);
os_path_join(&test_zig_dir, &std_buf, &test_std_dir);
- os_path_join(&test_std_dir, &index_zig_buf, &test_index_file);
+ os_path_join(&test_std_dir, &std_zig_buf, &test_index_file);
int err;
bool exists;
diff --git a/src/ir.cpp b/src/ir.cpp
index 87e03ea51910c31aceb946897b9f1365587dfa20..5b1b9d9bff09c23bcb178971b9dbe44885ca1f26 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -258,7 +258,6 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
case ZigTypeIdPointer:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdErrorSet:
case ZigTypeIdOpaque:
@@ -1123,11 +1122,11 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *
return &const_instruction->base;
}
-static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) {
+static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigType *import) {
IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node);
- const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace;
+ const_instruction->base.value.type = irb->codegen->builtin_types.entry_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_import = import;
+ const_instruction->base.value.data.x_type = import;
return &const_instruction->base;
}
@@ -3824,7 +3823,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
if (tld)
return ir_build_decl_ref(irb, scope, node, tld, lval);
- if (node->owner->any_imports_failed) {
+ if (get_container_scope(node->owner)->any_imports_failed) {
// skip the error message since we had a failing import in this file
// if an import breaks we don't need redundant undeclared identifier errors
return irb->codegen->invalid_instruction;
@@ -6609,20 +6608,32 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
return true;
}
-static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {
+static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name,
+ Scope *scope, AstNode *source_node, Buf *out_bare_name)
+{
if (exec->name) {
- return exec->name;
+ ZigType *import = get_scope_import(scope);
+ Buf *namespace_name = buf_create_from_buf(&import->name);
+ if (buf_len(namespace_name) != 0) buf_append_char(namespace_name, NAMESPACE_SEP_CHAR);
+ buf_append_buf(namespace_name, exec->name);
+ buf_init_from_buf(out_bare_name, exec->name);
+ return namespace_name;
} else if (exec->name_fn != nullptr) {
Buf *name = buf_alloc();
buf_append_buf(name, &exec->name_fn->symbol_name);
buf_appendf(name, "(");
render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
buf_appendf(name, ")");
+ buf_init_from_buf(out_bare_name, name);
return name;
} else {
- //Note: C-imports do not have valid location information
- return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
- (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
+ ZigType *import = get_scope_import(scope);
+ Buf *namespace_name = buf_create_from_buf(&import->name);
+ if (buf_len(namespace_name) != 0) buf_append_char(namespace_name, NAMESPACE_SEP_CHAR);
+ buf_appendf(namespace_name, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize, kind_name,
+ source_node->line + 1, source_node->column + 1);
+ buf_init_from_buf(out_bare_name, namespace_name);
+ return namespace_name;
}
}
@@ -6630,24 +6641,23 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
assert(node->type == NodeTypeContainerDecl);
ContainerKind kind = node->data.container_decl.kind;
- Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node);
-
- VisibMod visib_mod = VisibModPub;
- TldContainer *tld_container = allocate(1);
- init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, parent_scope);
+ Buf *bare_name = buf_alloc();
+ Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), parent_scope, node, bare_name);
ContainerLayout layout = node->data.container_decl.layout;
ZigType *container_type = get_partial_container_type(irb->codegen, parent_scope,
- kind, node, buf_ptr(name), layout);
+ kind, node, buf_ptr(name), bare_name, layout);
ScopeDecls *child_scope = get_container_scope(container_type);
- tld_container->type_entry = container_type;
- tld_container->decls_scope = child_scope;
-
for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) {
AstNode *child_node = node->data.container_decl.decls.at(i);
scan_decls(irb->codegen, child_scope, child_node);
}
+
+ TldContainer *tld_container = allocate(1);
+ init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope);
+ tld_container->type_entry = container_type;
+ tld_container->decls_scope = child_scope;
irb->codegen->resolve_queue.append(&tld_container->base);
// 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
uint32_t err_count = node->data.err_set_decl.decls.length;
- Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node);
+ Buf bare_name = BUF_INIT;
+ Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", parent_scope, node, &bare_name);
ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
buf_init_from_buf(&err_set_type->name, type_name);
err_set_type->data.error_set.err_count = err_count;
@@ -12065,7 +12076,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
case ZigTypeIdOpaque:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -13407,7 +13417,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdErrorSet:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -13432,7 +13441,6 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case ZigTypeIdErrorSet:
case ZigTypeIdVector:
zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
@@ -14616,7 +14624,6 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdPromise:
@@ -15368,7 +15375,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
auto entry = container_scope->decl_table.maybe_get(field_name);
Tld *tld = entry ? entry->value : nullptr;
if (tld && tld->id == TldIdFn) {
- resolve_top_level_decl(ira->codegen, tld, false, source_instr->source_node);
+ resolve_top_level_decl(ira->codegen, tld, source_instr->source_node);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
TldFn *tld_fn = (TldFn *)tld;
@@ -15557,8 +15564,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name,
static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
- bool pointer_only = false;
- resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);
+ resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
@@ -15735,12 +15741,17 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
}
}
ScopeDecls *container_scope = get_container_scope(child_type);
- if (container_scope != nullptr) {
- auto entry = container_scope->decl_table.maybe_get(field_name);
- Tld *tld = entry ? entry->value : nullptr;
- if (tld) {
- return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
+ Tld *tld = find_container_decl(ira->codegen, container_scope, field_name);
+ if (tld) {
+ if (tld->visib_mod == VisibModPrivate &&
+ tld->import != get_scope_import(field_ptr_instruction->base.scope))
+ {
+ ErrorMsg *msg = ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("'%s' is private", buf_ptr(field_name)));
+ add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
+ return ira->codegen->invalid_instruction;
}
+ return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
}
if (child_type->id == ZigTypeIdUnion &&
(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
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
}
}
+ const char *container_name = (child_type == ira->codegen->root_import) ?
+ "root source file" : buf_ptr(buf_sprintf("container '%s'", buf_ptr(&child_type->name)));
ir_add_error(ira, &field_ptr_instruction->base,
- buf_sprintf("container '%s' has no member called '%s'",
- buf_ptr(&child_type->name), buf_ptr(field_name)));
+ buf_sprintf("%s has no member called '%s'",
+ container_name, buf_ptr(field_name)));
return ira->codegen->invalid_instruction;
} else if (child_type->id == ZigTypeIdErrorSet) {
ErrorTableEntry *err_entry;
@@ -15971,37 +15984,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
return ira->codegen->invalid_instruction;
}
- } else if (container_type->id == ZigTypeIdNamespace) {
- assert(container_ptr->value.type->id == ZigTypeIdPointer);
- ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
- if (!container_ptr_val)
- return ira->codegen->invalid_instruction;
-
- ConstExprValue *namespace_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val,
- field_ptr_instruction->base.source_node);
- if (namespace_val == nullptr)
- return ira->codegen->invalid_instruction;
- assert(namespace_val->special == ConstValSpecialStatic);
-
- ImportTableEntry *namespace_import = namespace_val->data.x_import;
-
- Tld *tld = find_decl(ira->codegen, &namespace_import->decls_scope->base, field_name);
- if (tld) {
- if (tld->visib_mod == VisibModPrivate &&
- tld->import != source_node->owner)
- {
- ErrorMsg *msg = ir_add_error_node(ira, source_node,
- buf_sprintf("'%s' is private", buf_ptr(field_name)));
- add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
- return ira->codegen->invalid_instruction;
- }
- return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld);
- } else {
- const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)";
- ir_add_error_node(ira, source_node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), import_name));
- return ira->codegen->invalid_instruction;
- }
} else {
ir_add_error_node(ira, field_ptr_instruction->base.source_node,
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,
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdPromise:
case ZigTypeIdVector:
@@ -16402,7 +16383,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdPromise:
case ZigTypeIdVector:
@@ -16452,7 +16432,6 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
case ZigTypeIdComptimeInt:
case ZigTypeIdBoundFn:
case ZigTypeIdMetaType:
- case ZigTypeIdNamespace:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
ir_add_error_node(ira, size_of_instruction->base.source_node,
@@ -16860,7 +16839,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdPointer:
case ZigTypeIdPromise:
case ZigTypeIdFn:
- case ZigTypeIdNamespace:
case ZigTypeIdErrorSet: {
if (pointee_val) {
IrInstruction *result = ir_const(ira, &switch_target_instruction->base, nullptr);
@@ -17009,25 +16987,29 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
return ira->codegen->invalid_instruction;
AstNode *source_node = import_instruction->base.source_node;
- ImportTableEntry *import = source_node->owner;
+ ZigType *import = source_node->owner;
Buf *import_target_path;
Buf *search_dir;
- assert(import->package);
- PackageTableEntry *target_package;
- auto package_entry = import->package->package_table.maybe_get(import_target_str);
+ assert(import->data.structure.root_struct->package);
+ ZigPackage *target_package;
+ auto package_entry = import->data.structure.root_struct->package->package_table.maybe_get(import_target_str);
+ SourceKind source_kind;
if (package_entry) {
target_package = package_entry->value;
import_target_path = &target_package->root_src_path;
search_dir = &target_package->root_src_dir;
+ source_kind = SourceKindPkgMain;
} else {
// try it as a filename
- target_package = import->package;
+ target_package = import->data.structure.root_struct->package;
import_target_path = import_target_str;
// search relative to importing file
search_dir = buf_alloc();
- os_path_dirname(import->path, search_dir);
+ os_path_dirname(import->data.structure.root_struct->path, search_dir);
+
+ source_kind = SourceKindNonRoot;
}
Buf full_path = BUF_INIT;
@@ -17041,10 +17023,19 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
auto import_entry = ira->codegen->import_table.maybe_get(resolved_path);
if (import_entry) {
- IrInstruction *result = ir_const(ira, &import_instruction->base,
- ira->codegen->builtin_types.entry_namespace);
- result->value.data.x_import = import_entry->value;
- return result;
+ return ir_const_type(ira, &import_instruction->base, import_entry->value);
+ }
+
+ if (source_kind == SourceKindNonRoot) {
+ ZigPackage *cur_scope_pkg = scope_package(import_instruction->base.scope);
+ Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir;
+ Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1);
+ if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("import of file outside package path: '%s'",
+ buf_ptr(import_target_path)));
+ return ira->codegen->invalid_instruction;
+ }
}
if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
@@ -17059,13 +17050,9 @@ static IrInstruction *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructio
}
}
- ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);
+ ZigType *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code, source_kind);
- scan_import(ira->codegen, target_import);
-
- IrInstruction *result = ir_const(ira, &import_instruction->base, ira->codegen->builtin_types.entry_namespace);
- result->value.data.x_import = target_import;
- return result;
+ return ir_const_type(ira, &import_instruction->base, target_import);
}
static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {
@@ -17398,17 +17385,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
return ira->codegen->invalid_instruction;
ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf);
- size_t i = ira->codegen->tld_ref_source_node_stack.length;
- for (;;) {
- if (i == 0)
- break;
- i -= 1;
- AstNode *source_node = ira->codegen->tld_ref_source_node_stack.at(i);
- if (source_node) {
- add_error_note(ira->codegen, msg, source_node,
- buf_sprintf("referenced here"));
- }
- }
+ emit_error_notes_for_ref_stack(ira->codegen, msg);
return ira->codegen->invalid_instruction;
}
@@ -17665,6 +17642,12 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
return ir_const_unsigned(ira, &instruction->base, bit_offset);
}
+static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) {
+ ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected"));
+ emit_error_notes_for_ref_stack(ira->codegen, msg);
+ return ira->codegen->invalid_instruction;
+}
+
static void ensure_field_index(ZigType *type, const char *field_name, size_t index) {
Buf *field_name_buf;
@@ -17711,7 +17694,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
return var->const_value->data.x_type;
}
-static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) {
+static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val,
+ ScopeDecls *decls_scope)
+{
Error err;
ZigType *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr);
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
while ((curr_entry = decl_it.next()) != nullptr) {
// If the definition is unresolved, force it to be resolved again.
if (curr_entry->value->resolution == TldResolutionUnresolved) {
- resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node);
+ resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node);
if (curr_entry->value->resolution != TldResolutionOk) {
return ErrorSemanticAnalyzeFail;
}
@@ -17831,6 +17816,11 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
assert(!fn_entry->is_test);
+ if (fn_entry->type_entry == nullptr) {
+ ir_error_dependency_loop(ira, source_instr);
+ return ErrorSemanticAnalyzeFail;
+ }
+
AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node);
ConstExprValue *fn_def_val = create_const_vals(1);
@@ -18007,7 +17997,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
// alignment: u32
ensure_field_index(result->type, "alignment", 3);
fields[3].special = ConstValSpecialStatic;
- fields[3].type = get_int_type(ira->codegen, false, 29);
+ fields[3].type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type));
// child: type
ensure_field_index(result->type, "child", 4);
@@ -18026,7 +18016,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,
ConstExprValue *inner_fields = create_const_vals(2);
inner_fields[1].special = ConstValSpecialStatic;
- inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
+ inner_fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
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,
enum_field_val->data.x_struct.fields = inner_fields;
}
-static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigType *type_entry, ConstExprValue **out) {
+static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry,
+ ConstExprValue **out)
+{
Error err;
assert(type_entry != nullptr);
assert(!type_is_invalid(type_entry));
@@ -18056,7 +18048,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
*out = nullptr;
@@ -18089,7 +18080,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
// bits: u8
ensure_field_index(result->type, "bits", 1);
fields[1].special = ConstValSpecialStatic;
- fields[1].type = ira->codegen->builtin_types.entry_u8;
+ fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&fields[1].data.x_bigint, type_entry->data.integral.bit_count);
break;
@@ -18106,7 +18097,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
// bits: u8
ensure_field_index(result->type, "bits", 0);
fields[0].special = ConstValSpecialStatic;
- fields[0].type = ira->codegen->builtin_types.entry_u8;
+ fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&fields->data.x_bigint, type_entry->data.floating.bit_count);
break;
@@ -18130,7 +18121,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
// len: usize
ensure_field_index(result->type, "len", 0);
fields[0].special = ConstValSpecialStatic;
- fields[0].type = ira->codegen->builtin_types.entry_usize;
+ fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.array.len);
// child: type
ensure_field_index(result->type, "child", 1);
@@ -18151,7 +18142,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
// len: usize
ensure_field_index(result->type, "len", 0);
fields[0].special = ConstValSpecialStatic;
- fields[0].type = ira->codegen->builtin_types.entry_u32;
+ fields[0].type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);
// child: type
ensure_field_index(result->type, "child", 1);
@@ -18248,8 +18239,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
- if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope)))
+ if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3],
+ type_entry->data.enumeration.decls_scope)))
+ {
return err;
+ }
break;
}
@@ -18266,11 +18260,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
ensure_field_index(result->type, "errors", 0);
ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr);
- if (!resolve_inferred_error_set(ira->codegen, type_entry, source_node)) {
+ if (!resolve_inferred_error_set(ira->codegen, type_entry, source_instr->source_node)) {
return ErrorSemanticAnalyzeFail;
}
if (type_is_global_error_set(type_entry)) {
- ir_add_error_node(ira, source_node,
+ ir_add_error(ira, source_instr,
buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936"));
return ErrorSemanticAnalyzeFail;
}
@@ -18292,7 +18286,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
ConstExprValue *inner_fields = create_const_vals(2);
inner_fields[1].special = ConstValSpecialStatic;
- inner_fields[1].type = ira->codegen->builtin_types.entry_usize;
+ inner_fields[1].type = ira->codegen->builtin_types.entry_num_lit_int;
ConstExprValue *name = nullptr;
if (error->cached_error_name_val != nullptr)
@@ -18412,8 +18406,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
- if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope)))
+ if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3],
+ type_entry->data.unionation.decls_scope)))
+ {
return err;
+ }
break;
}
@@ -18461,7 +18458,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
ConstExprValue *inner_fields = create_const_vals(3);
inner_fields[1].special = ConstValSpecialStatic;
- inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
+ inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
if (!type_has_bits(struct_field->type_entry)) {
inner_fields[1].data.x_optional = nullptr;
@@ -18487,8 +18484,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 2);
- if ((err = ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope)))
+ if ((err = ir_make_type_info_defs(ira, source_instr, &fields[2],
+ type_entry->data.structure.decls_scope)))
+ {
return err;
+ }
break;
}
@@ -18600,7 +18600,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigTy
{
ZigType *fn_type = type_entry->data.bound_fn.fn_type;
assert(fn_type->id == ZigTypeIdFn);
- if ((err = ir_make_type_info_value(ira, source_node, fn_type, &result)))
+ if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
return err;
break;
@@ -18625,7 +18625,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr);
ConstExprValue *payload;
- if ((err = ir_make_type_info_value(ira, instruction->base.source_node, type_entry, &payload)))
+ if ((err = ir_make_type_info_value(ira, &instruction->base, type_entry, &payload)))
return ira->codegen->invalid_instruction;
IrInstruction *result = ir_const(ira, &instruction->base, result_type);
@@ -18680,7 +18680,7 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
if (!type_entry->cached_const_name_val) {
- type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, &type_entry->name);
+ type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, type_bare_name(type_entry));
}
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
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
if (type_is_invalid(cimport_result->type))
return ira->codegen->invalid_instruction;
- ImportTableEntry *child_import = allocate(1);
- child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import);
- child_import->c_import_node = node;
- child_import->package = new_anonymous_package();
- child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
- child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
- child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
+ ZigPackage *cur_scope_pkg = scope_package(instruction->base.scope);
+ Buf *namespace_name = buf_sprintf("%s.cimport:%" ZIG_PRI_usize ":%" ZIG_PRI_usize,
+ buf_ptr(&cur_scope_pkg->pkg_path), node->line + 1, node->column + 1);
+
+ RootStruct *root_struct = allocate(1);
+ root_struct->package = new_anonymous_package();
+ root_struct->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package);
+ root_struct->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
+ root_struct->c_import_node = node;
+ // TODO create namespace_name file in zig-cache instead of /tmp and use it
+ // for this DIFile
+ root_struct->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder,
buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str(".")));
+ ZigType *child_import = get_root_container_type(ira->codegen, buf_ptr(namespace_name),
+ namespace_name, root_struct);
ZigList errors = {0};
@@ -18738,14 +18745,12 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
if (ira->codegen->verbose_cimport) {
fprintf(stderr, "\nC imports:\n");
fprintf(stderr, "-----------\n");
- ast_render(ira->codegen, stderr, child_import->root, 4);
+ ast_render(ira->codegen, stderr, child_import->data.structure.decl_node, 4);
}
- scan_decls(ira->codegen, child_import->decls_scope, child_import->root);
+ scan_decls(ira->codegen, get_container_scope(child_import), child_import->data.structure.decl_node);
- IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_namespace);
- result->value.data.x_import = child_import;
- return result;
+ return ir_const_type(ira, &instruction->base, child_import);
}
static IrInstruction *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
@@ -18819,10 +18824,10 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
if (!rel_file_path)
return ira->codegen->invalid_instruction;
- ImportTableEntry *import = get_scope_import(instruction->base.scope);
+ ZigType *import = get_scope_import(instruction->base.scope);
// figure out absolute path to resource
Buf source_dir_path = BUF_INIT;
- os_path_dirname(import->path, &source_dir_path);
+ os_path_dirname(import->data.structure.root_struct->path, &source_dir_path);
Buf *resolve_paths[] = {
&source_dir_path,
@@ -19752,6 +19757,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
} else {
+ if (array_type->data.pointer.ptr_len == PtrLenC) {
+ array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
+ }
return_type = get_slice_type(ira->codegen, array_type);
if (!end) {
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
static IrInstruction *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) {
IrInstruction *result = ir_build_return_address(&ira->new_irb,
instruction->base.scope, instruction->base.source_node);
- ZigType *u8 = ira->codegen->builtin_types.entry_u8;
- ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
- result->value.type = u8_ptr_const;
+ result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
}
static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) {
IrInstruction *result = ir_build_frame_address(&ira->new_irb,
instruction->base.scope, instruction->base.source_node);
- ZigType *u8 = ira->codegen->builtin_types.entry_u8;
- ZigType *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
- result->value.type = u8_ptr_const;
+ result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
}
@@ -20179,7 +20183,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
case ZigTypeIdVoid:
@@ -21025,7 +21028,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
case ZigTypeIdOpaque:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
@@ -21185,7 +21187,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
case ZigTypeIdOpaque:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
@@ -21343,7 +21344,6 @@ static bool type_can_bit_cast(ZigType *t) {
case ZigTypeIdOpaque:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
case ZigTypeIdUnreachable:
case ZigTypeIdComptimeFloat:
case ZigTypeIdComptimeInt:
@@ -21516,7 +21516,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
Tld *tld = instruction->tld;
LVal lval = instruction->lval;
- resolve_top_level_decl(ira->codegen, tld, lval == LValPtr, instruction->base.source_node);
+ resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
@@ -21528,6 +21528,10 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
TldVar *tld_var = (TldVar *)tld;
ZigVar *var = tld_var->var;
+ if (var == nullptr) {
+ return ir_error_dependency_loop(ira, &instruction->base);
+ }
+
IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
if (type_is_invalid(var_ptr->value.type))
return ira->codegen->invalid_instruction;
@@ -21664,9 +21668,11 @@ static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstru
}
static IrInstruction *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstructionOpaqueType *instruction) {
- Buf *name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque", instruction->base.source_node);
+ Buf *bare_name = buf_alloc();
+ Buf *full_name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque",
+ instruction->base.scope, instruction->base.source_node, bare_name);
ZigType *result_type = get_opaque_type(ira->codegen, instruction->base.scope, instruction->base.source_node,
- buf_ptr(name));
+ buf_ptr(full_name), bare_name);
return ir_const_type(ira, &instruction->base, result_type);
}
diff --git a/src/link.cpp b/src/link.cpp
index 7eb8cb111f76473c1d36e11b08940e54e6c24c4f..bd1879da1ae8412a2ca911ec0d1e417ecd620c3e 100644
--- a/src/link.cpp
+++ b/src/link.cpp
@@ -41,7 +41,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
child_out_type = OutTypeObj;
}
- CodeGen *child_gen = codegen_create(full_path, parent_gen->zig_target, child_out_type,
+ CodeGen *child_gen = codegen_create(nullptr, full_path, parent_gen->zig_target, child_out_type,
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,
parent_gen->libc);
@@ -87,10 +87,8 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) {
}
static Buf *build_compiler_rt(CodeGen *parent_gen) {
- Buf *dir_path = buf_alloc();
- os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt"), dir_path);
Buf *full_path = buf_alloc();
- os_path_join(dir_path, buf_create_from_str("index.zig"), full_path);
+ os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt.zig"), full_path);
return build_a_raw(parent_gen, "compiler_rt", full_path);
}
diff --git a/src/main.cpp b/src/main.cpp
index d2099a9f80c79243b4a99658805b60ee2740aa09..9078059dc52d29a50e706210d2b7ba24e2339d0f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -63,6 +63,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
" --output-lib [file] override import library path\n"
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
" --pkg-end pop current pkg\n"
+ " --main-pkg-path set the directory of the root package\n"
" --release-fast build with optimizations on and safety off\n"
" --release-safe build with optimizations on and safety on\n"
" --release-small build with size optimizations on and safety off\n"
@@ -215,7 +216,7 @@ struct CliPkg {
CliPkg *parent;
};
-static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
+static void add_package(CodeGen *g, CliPkg *cli_pkg, ZigPackage *pkg) {
for (size_t i = 0; i < cli_pkg->children.length; i += 1) {
CliPkg *child_cli_pkg = cli_pkg->children.at(i);
@@ -223,10 +224,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
Buf *basename = buf_alloc();
os_path_split(buf_create_from_str(child_cli_pkg->path), dirname, basename);
- PackageTableEntry *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename));
+ ZigPackage *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename),
+ buf_ptr(buf_sprintf("%s.%s", buf_ptr(&pkg->pkg_path), child_cli_pkg->name)));
auto entry = pkg->package_table.put_unique(buf_create_from_str(child_cli_pkg->name), child_pkg);
if (entry) {
- PackageTableEntry *existing_pkg = entry->value;
+ ZigPackage *existing_pkg = entry->value;
Buf *full_path = buf_alloc();
os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path);
fprintf(stderr, "Unable to add package '%s'->'%s': already exists as '%s'\n",
@@ -437,6 +439,7 @@ int main(int argc, char **argv) {
TargetSubsystem subsystem = TargetSubsystemAuto;
bool is_single_threaded = false;
Buf *override_std_dir = nullptr;
+ Buf *main_pkg_path = nullptr;
ValgrindSupport valgrind_support = ValgrindSupportAuto;
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
@@ -475,8 +478,8 @@ int main(int argc, char **argv) {
ZigTarget target;
get_native_target(&target);
- CodeGen *g = codegen_create(build_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
- override_std_dir, nullptr);
+ CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe,
+ BuildModeDebug, get_zig_lib_dir(), override_std_dir, nullptr);
g->valgrind_support = valgrind_support;
g->enable_time_report = timing_info;
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) {
return EXIT_FAILURE;
}
- PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
- buf_ptr(&build_file_basename));
+ ZigPackage *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
+ buf_ptr(&build_file_basename), "std.special");
g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
g->enable_cache = get_cache_opt(enable_cache, true);
codegen_build_and_link(g);
@@ -566,8 +569,8 @@ int main(int argc, char **argv) {
get_native_target(&target);
Buf *fmt_runner_path = buf_alloc();
os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
- CodeGen *g = codegen_create(fmt_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
- nullptr, nullptr);
+ CodeGen *g = codegen_create(main_pkg_path, fmt_runner_path, &target, OutTypeExe,
+ BuildModeDebug, get_zig_lib_dir(), nullptr, nullptr);
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
g->valgrind_support = valgrind_support;
g->is_single_threaded = true;
@@ -728,6 +731,8 @@ int main(int argc, char **argv) {
llvm_argv.append(argv[i]);
} else if (strcmp(arg, "--override-std-dir") == 0) {
override_std_dir = buf_create_from_str(argv[i]);
+ } else if (strcmp(arg, "--main-pkg-path") == 0) {
+ main_pkg_path = buf_create_from_str(argv[i]);
} else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
lib_dirs.append(argv[i]);
} else if (strcmp(arg, "--library") == 0) {
@@ -907,8 +912,8 @@ int main(int argc, char **argv) {
return EXIT_SUCCESS;
}
case CmdBuiltin: {
- CodeGen *g = codegen_create(nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir,
- nullptr);
+ CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
+ out_type, build_mode, get_zig_lib_dir(), override_std_dir, nullptr);
g->valgrind_support = valgrind_support;
g->is_single_threaded = is_single_threaded;
Buf *builtin_source = codegen_generate_builtin_source(g);
@@ -1011,8 +1016,8 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
}
- CodeGen *g = codegen_create(zig_root_source_file, &target, out_type, build_mode, get_zig_lib_dir(),
- override_std_dir, libc);
+ CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
+ get_zig_lib_dir(), override_std_dir, libc);
g->valgrind_support = valgrind_support;
g->subsystem = subsystem;
@@ -1095,7 +1100,6 @@ int main(int argc, char **argv) {
if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
-
add_package(g, cur_pkg, g->root_package);
if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
@@ -1145,7 +1149,7 @@ int main(int argc, char **argv) {
}
} else if (cmd == CmdTranslateC) {
codegen_translate_c(g, in_file_buf);
- ast_render(g, stdout, g->root_import->root, 4);
+ ast_render(g, stdout, g->root_import->data.structure.decl_node, 4);
if (timing_info)
codegen_print_timing_report(g, stdout);
return EXIT_SUCCESS;
diff --git a/src/os.cpp b/src/os.cpp
index 732baea359fdb41623e563409ac979657ea2c66b..e418aa2c29454227d7d3d9b84e7db02f37986bbd 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -264,7 +264,7 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
buf_append_buf(out_full_path, basename);
}
-int os_path_real(Buf *rel_path, Buf *out_abs_path) {
+Error os_path_real(Buf *rel_path, Buf *out_abs_path) {
#if defined(ZIG_OS_WINDOWS)
buf_resize(out_abs_path, 4096);
if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) {
diff --git a/src/os.hpp b/src/os.hpp
index c4fae1d62be3256fb6263e4a44feff772045df8e..2e0b1ea88fa17d85942515b64f16728c64a144b6 100644
--- a/src/os.hpp
+++ b/src/os.hpp
@@ -96,7 +96,7 @@ void os_path_dirname(Buf *full_path, Buf *out_dirname);
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
-int os_path_real(Buf *rel_path, Buf *out_abs_path);
+Error os_path_real(Buf *rel_path, Buf *out_abs_path);
Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
bool os_path_is_absolute(Buf *path);
diff --git a/src/parser.cpp b/src/parser.cpp
index 6fe78c14c341b0d8c454ecfc4909fba026c668b4..2fd453c67fc46364884adff53641cafdeff22e80 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -18,7 +18,7 @@ struct ParseContext {
Buf *buf;
size_t current_token;
ZigList *tokens;
- ImportTableEntry *owner;
+ ZigType *owner;
ErrColor err_color;
};
@@ -130,8 +130,10 @@ static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
va_end(ap);
- ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column,
- pc->owner->source_code, pc->owner->line_offsets, msg);
+ ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
+ token->start_line, token->start_column,
+ pc->owner->data.structure.root_struct->source_code,
+ pc->owner->data.structure.root_struct->line_offsets, msg);
err->line_start = token->start_line;
err->column_start = token->start_column;
@@ -148,8 +150,10 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, size_t offset, const
Buf *msg = buf_vprintf(format, ap);
va_end(ap);
- ErrorMsg *err = err_msg_create_with_line(pc->owner->path, node->line, node->column,
- pc->owner->source_code, pc->owner->line_offsets, msg);
+ ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path,
+ node->line, node->column,
+ pc->owner->data.structure.root_struct->source_code,
+ pc->owner->data.structure.root_struct->line_offsets, msg);
print_err_msg(err, pc->err_color);
exit(EXIT_FAILURE);
@@ -570,9 +574,7 @@ static void ast_parse_asm_template(ParseContext *pc, AstNode *node) {
}
}
-AstNode *ast_parse(Buf *buf, ZigList *tokens, ImportTableEntry *owner,
- ErrColor err_color)
-{
+AstNode *ast_parse(Buf *buf, ZigList *tokens, ZigType *owner, ErrColor err_color) {
ParseContext pc = {};
pc.err_color = err_color;
pc.owner = owner;
diff --git a/src/parser.hpp b/src/parser.hpp
index 7243431e4fccd065b9985c62b9701b6dd33860f3..73950993f39421b0d80a5a3afaac7d38a91e07c2 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -16,7 +16,7 @@ ATTRIBUTE_PRINTF(2, 3)
void ast_token_error(Token *token, const char *format, ...);
-AstNode * ast_parse(Buf *buf, ZigList *tokens, ImportTableEntry *owner, ErrColor err_color);
+AstNode * ast_parse(Buf *buf, ZigList *tokens, ZigType *owner, ErrColor err_color);
void ast_print(AstNode *node, int indent);
diff --git a/src/target.cpp b/src/target.cpp
index 852f55ef7d1cec026ca98f7338a67cffda77b616..a662d9e6fc1d897e5dce42cb421eecb6ecdc62d1 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -676,15 +676,15 @@ Error target_parse_triple(ZigTarget *target, const char *triple) {
if (!opt_archsub.is_some)
return ErrorMissingArchitecture;
- if (!opt_os.is_some)
- return ErrorMissingOperatingSystem;
-
if ((err = target_parse_archsub(&target->arch, &target->sub_arch,
(char*)opt_archsub.value.ptr, opt_archsub.value.len)))
{
return err;
}
+ if (!opt_os.is_some)
+ return ErrorMissingOperatingSystem;
+
if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
return err;
}
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index 765ad32e29a58983fb742f9e86f32c390098daa9..25c5c1a14bce62c011a5a78994c2822c933c1d9d 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -76,7 +76,7 @@ struct TransScopeWhile {
};
struct Context {
- ImportTableEntry *import;
+ ZigType *import;
ZigList *errors;
VisibMod visib_mod;
bool want_export;
@@ -4779,7 +4779,7 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {
}
}
-Error parse_h_buf(ImportTableEntry *import, ZigList *errors, Buf *source,
+Error parse_h_buf(ZigType *import, ZigList *errors, Buf *source,
CodeGen *codegen, AstNode *source_node)
{
Error err;
@@ -4795,7 +4795,7 @@ Error parse_h_buf(ImportTableEntry *import, ZigList *errors, Buf *so
return err;
}
-Error parse_h_file(ImportTableEntry *import, ZigList *errors, const char *target_file,
+Error parse_h_file(ZigType *import, ZigList *errors, const char *target_file,
CodeGen *codegen, AstNode *source_node)
{
Context context = {0};
@@ -5005,7 +5005,8 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const
render_macros(c);
render_aliases(c);
- import->root = c->root;
+ import->data.structure.decl_node = c->root;
+ import->data.structure.decls_scope->base.source_node = c->root;
return ErrorNone;
}
diff --git a/src/translate_c.hpp b/src/translate_c.hpp
index 4323e98c1eca3e4f6b246011b8460e0be5b421ad..c4bd270c21bc003ffa7613bd33c3219346339a2a 100644
--- a/src/translate_c.hpp
+++ b/src/translate_c.hpp
@@ -11,10 +11,10 @@
#include "all_types.hpp"
-Error parse_h_file(ImportTableEntry *import, ZigList *errors, const char *target_file,
+Error parse_h_file(ZigType *import, ZigList *errors, const char *target_file,
CodeGen *codegen, AstNode *source_node);
-Error parse_h_buf(ImportTableEntry *import, ZigList *errors, Buf *source,
+Error parse_h_buf(ZigType *import, ZigList *errors, Buf *source,
CodeGen *codegen, AstNode *source_node);
#endif
diff --git a/src/util.hpp b/src/util.hpp
index a0e759567ea3caeb9d798d77e68662e9b86944f7..abf4d37c883c257ef8692e8fde8ce47f40a35f63 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -93,18 +93,6 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
return ptr;
}
-template
-static inline void safe_memcpy(T *dest, const T *src, size_t count) {
-#ifdef NDEBUG
- memcpy(dest, src, count * sizeof(T));
-#else
- // manually assign every elment to trigger compile error for non-copyable structs
- for (size_t i = 0; i < count; i += 1) {
- dest[i] = src[i];
- }
-#endif
-}
-
template
static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
T *ptr = reallocate_nonzero(old, old_count, new_count);
diff --git a/std/array_list.zig b/std/array_list.zig
index e2535d639337558dd2af34ec1d76a9275820f330..2c9da50972049ce491283c620e7c9bca3d7bbd17 100644
--- a/std/array_list.zig
+++ b/std/array_list.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
@@ -406,6 +406,6 @@ const Item = struct {
test "std.ArrayList: ArrayList(T) of struct T" {
var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
- try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
+ try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) });
testing.expect(root.sub_items.items[0].integer == 42);
}
diff --git a/std/atomic.zig b/std/atomic.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6f7b4fe75d1defdf2ee8d7ecc60cce89398c31d6
--- /dev/null
+++ b/std/atomic.zig
@@ -0,0 +1,9 @@
+pub const Stack = @import("atomic/stack.zig").Stack;
+pub const Queue = @import("atomic/queue.zig").Queue;
+pub const Int = @import("atomic/int.zig").Int;
+
+test "std.atomic" {
+ _ = @import("atomic/stack.zig");
+ _ = @import("atomic/queue.zig");
+ _ = @import("atomic/int.zig");
+}
diff --git a/std/atomic/index.zig b/std/atomic/index.zig
deleted file mode 100644
index a94cff19733efc82d340ffe5357e2144b06f3671..0000000000000000000000000000000000000000
--- a/std/atomic/index.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-pub const Stack = @import("stack.zig").Stack;
-pub const Queue = @import("queue.zig").Queue;
-pub const Int = @import("int.zig").Int;
-
-test "std.atomic" {
- _ = @import("stack.zig");
- _ = @import("queue.zig");
- _ = @import("int.zig");
-}
diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig
index bdc86c0981ab43ee2d9111692bdcf013e4896cb2..431a96e64b2eead1ee33da96b08eab1705f5062f 100644
--- a/std/atomic/queue.zig
+++ b/std/atomic/queue.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const AtomicOrder = builtin.AtomicOrder;
const AtomicRmwOp = builtin.AtomicRmwOp;
diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig
index 4d0d5075e048061798d93cf666a5293c17203f12..8ae6c997aad6c2ab6ee7328b530b3ca7dc9a88f5 100644
--- a/std/atomic/stack.zig
+++ b/std/atomic/stack.zig
@@ -68,7 +68,7 @@ pub fn Stack(comptime T: type) type {
};
}
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const Context = struct {
allocator: *std.mem.Allocator,
stack: *Stack(i32),
diff --git a/std/base64.zig b/std/base64.zig
index cfe8ea95f88ae41570715657477f8cddfa0fb6b0..0e44f9d4fef1ebf4da99dd5aedc3534fdc76778e 100644
--- a/std/base64.zig
+++ b/std/base64.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
diff --git a/std/buf_map.zig b/std/buf_map.zig
index f8d3d5e04de45ae015109e35af84273a8955d607..be0666d972fad6e39b957f3780b4bc7516f88fca 100644
--- a/std/buf_map.zig
+++ b/std/buf_map.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const HashMap = std.HashMap;
const mem = std.mem;
const Allocator = mem.Allocator;
diff --git a/std/buf_set.zig b/std/buf_set.zig
index 484b4953b922f57ba76e846214298a67ff248db3..807b9db35dda13bf9b3e66944439263d6c0bc27c 100644
--- a/std/buf_set.zig
+++ b/std/buf_set.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const HashMap = @import("hash_map.zig").HashMap;
const mem = @import("mem.zig");
const Allocator = mem.Allocator;
diff --git a/std/buffer.zig b/std/buffer.zig
index 371655f1e58c5401eeaccd59f2650ea487a9fd70..8706dfc320601dffd6902d00862e50f10e14b5a6 100644
--- a/std/buffer.zig
+++ b/std/buffer.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const mem = std.mem;
const Allocator = mem.Allocator;
diff --git a/std/build.zig b/std/build.zig
index e3fdfbcceea6e84bf4af01c5d53b21f29968a65a..2316a87b31e41b04d80f011ca685673deb63f87f 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const io = std.io;
const mem = std.mem;
@@ -859,6 +859,7 @@ pub const LibExeObjStep = struct {
verbose_cc: bool,
c_std: Builder.CStd,
override_std_dir: ?[]const u8,
+ main_pkg_path: ?[]const u8,
exec_cmd_args: ?[]const ?[]const u8,
name_prefix: []const u8,
filter: ?[]const u8,
@@ -950,6 +951,7 @@ pub const LibExeObjStep = struct {
.c_std = Builder.CStd.C99,
.system_linker_hack = false,
.override_std_dir = null,
+ .main_pkg_path = null,
.exec_cmd_args = null,
.name_prefix = "",
.filter = null,
@@ -1098,6 +1100,10 @@ pub const LibExeObjStep = struct {
self.override_std_dir = dir_path;
}
+ pub fn setMainPkgPath(self: *LibExeObjStep, dir_path: []const u8) void {
+ self.main_pkg_path = dir_path;
+ }
+
pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
self.output_path = file_path;
@@ -1320,7 +1326,7 @@ pub const LibExeObjStep = struct {
zig_args.append("--ver-patch") catch unreachable;
zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
}
- if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
+ if (self.static) {
zig_args.append("--static") catch unreachable;
}
@@ -1424,6 +1430,11 @@ pub const LibExeObjStep = struct {
try zig_args.append(builder.pathFromRoot(dir));
}
+ if (self.main_pkg_path) |dir| {
+ try zig_args.append("--main-pkg-path");
+ try zig_args.append(builder.pathFromRoot(dir));
+ }
+
try builder.spawnChild(zig_args.toSliceConst());
if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
diff --git a/std/build/fmt.zig b/std/build/fmt.zig
index ec0536dd340d45fe1508a5263595332945e1487e..f3b8e081804d3fb719455cb1bd19bef88a16a902 100644
--- a/std/build/fmt.zig
+++ b/std/build/fmt.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const build = @import("../build.zig");
const Step = build.Step;
const Builder = build.Builder;
diff --git a/std/c.zig b/std/c.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c7c8a9c5509d17dade6c1f5bc19a0e5910c77099
--- /dev/null
+++ b/std/c.zig
@@ -0,0 +1,68 @@
+const builtin = @import("builtin");
+const Os = builtin.Os;
+
+pub use switch (builtin.os) {
+ Os.linux => @import("c/linux.zig"),
+ Os.windows => @import("c/windows.zig"),
+ Os.macosx, Os.ios => @import("c/darwin.zig"),
+ Os.freebsd => @import("c/freebsd.zig"),
+ Os.netbsd => @import("c/netbsd.zig"),
+ else => empty_import,
+};
+const empty_import = @import("empty.zig");
+
+// TODO https://github.com/ziglang/zig/issues/265 on this whole file
+
+pub extern "c" fn abort() noreturn;
+pub extern "c" fn exit(code: c_int) noreturn;
+pub extern "c" fn isatty(fd: c_int) c_int;
+pub extern "c" fn close(fd: c_int) c_int;
+pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
+pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
+pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
+pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
+pub extern "c" fn raise(sig: c_int) c_int;
+pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
+pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
+pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
+pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
+pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
+pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
+pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
+pub extern "c" fn unlink(path: [*]const u8) c_int;
+pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
+pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
+pub extern "c" fn fork() c_int;
+pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
+pub extern "c" fn pipe(fds: *[2]c_int) c_int;
+pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
+pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
+pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
+pub extern "c" fn chdir(path: [*]const u8) c_int;
+pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
+pub extern "c" fn dup(fd: c_int) c_int;
+pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
+pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
+pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
+pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
+pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
+pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
+pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
+pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
+pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
+pub extern "c" fn rmdir(path: [*]const u8) c_int;
+
+pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
+pub extern "c" fn malloc(usize) ?*c_void;
+pub extern "c" fn realloc(*c_void, usize) ?*c_void;
+pub extern "c" fn free(*c_void) void;
+pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
+
+pub 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;
+pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
+pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
+pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
+pub extern "pthread" fn pthread_self() pthread_t;
+pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
+
+pub const pthread_t = *@OpaqueType();
diff --git a/std/c/darwin.zig b/std/c/darwin.zig
index 940d949985cbe31e2be2baa28ae3ff926129ee65..0e92e8d41111d5c4035c7e9eab86a6724ac32663 100644
--- a/std/c/darwin.zig
+++ b/std/c/darwin.zig
@@ -163,7 +163,7 @@ pub const Kevent = extern struct {
// sys/types.h on macos uses #pragma pack(4) so these checks are
// to make sure the struct is laid out the same. These values were
// produced from C code using the offsetof macro.
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
comptime {
diff --git a/std/c/index.zig b/std/c/index.zig
deleted file mode 100644
index 74cdd884cac0fac76194c15734a4877bbd70c9d6..0000000000000000000000000000000000000000
--- a/std/c/index.zig
+++ /dev/null
@@ -1,68 +0,0 @@
-const builtin = @import("builtin");
-const Os = builtin.Os;
-
-pub use switch (builtin.os) {
- Os.linux => @import("linux.zig"),
- Os.windows => @import("windows.zig"),
- Os.macosx, Os.ios => @import("darwin.zig"),
- Os.freebsd => @import("freebsd.zig"),
- Os.netbsd => @import("netbsd.zig"),
- else => empty_import,
-};
-const empty_import = @import("../empty.zig");
-
-// TODO https://github.com/ziglang/zig/issues/265 on this whole file
-
-pub extern "c" fn abort() noreturn;
-pub extern "c" fn exit(code: c_int) noreturn;
-pub extern "c" fn isatty(fd: c_int) c_int;
-pub extern "c" fn close(fd: c_int) c_int;
-pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
-pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
-pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
-pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
-pub extern "c" fn raise(sig: c_int) c_int;
-pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
-pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
-pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
-pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
-pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
-pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
-pub extern "c" fn munmap(addr: *c_void, len: usize) c_int;
-pub extern "c" fn unlink(path: [*]const u8) c_int;
-pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
-pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
-pub extern "c" fn fork() c_int;
-pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
-pub extern "c" fn pipe(fds: *[2]c_int) c_int;
-pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
-pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
-pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
-pub extern "c" fn chdir(path: [*]const u8) c_int;
-pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
-pub extern "c" fn dup(fd: c_int) c_int;
-pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
-pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
-pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
-pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
-pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
-pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
-pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
-pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
-pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
-pub extern "c" fn rmdir(path: [*]const u8) c_int;
-
-pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
-pub extern "c" fn malloc(usize) ?*c_void;
-pub extern "c" fn realloc(*c_void, usize) ?*c_void;
-pub extern "c" fn free(*c_void) void;
-pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
-
-pub 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;
-pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
-pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
-pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
-pub extern "pthread" fn pthread_self() pthread_t;
-pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
-
-pub const pthread_t = *@OpaqueType();
diff --git a/std/coff.zig b/std/coff.zig
index 53bd2a4b7a88a0a3a916205fe0f1b603d143956b..c31d2d8233b9985ef930485e9a34aafdbf6c9e8a 100644
--- a/std/coff.zig
+++ b/std/coff.zig
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
-const std = @import("index.zig");
+const std = @import("std.zig");
const io = std.io;
const mem = std.mem;
const os = std.os;
diff --git a/std/crypto.zig b/std/crypto.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2429441fc7932ca848ba8229fc2d3ca1032a885f
--- /dev/null
+++ b/std/crypto.zig
@@ -0,0 +1,45 @@
+pub const Md5 = @import("crypto/md5.zig").Md5;
+pub const Sha1 = @import("crypto/sha1.zig").Sha1;
+
+const sha2 = @import("crypto/sha2.zig");
+pub const Sha224 = sha2.Sha224;
+pub const Sha256 = sha2.Sha256;
+pub const Sha384 = sha2.Sha384;
+pub const Sha512 = sha2.Sha512;
+
+const sha3 = @import("crypto/sha3.zig");
+pub const Sha3_224 = sha3.Sha3_224;
+pub const Sha3_256 = sha3.Sha3_256;
+pub const Sha3_384 = sha3.Sha3_384;
+pub const Sha3_512 = sha3.Sha3_512;
+
+const blake2 = @import("crypto/blake2.zig");
+pub const Blake2s224 = blake2.Blake2s224;
+pub const Blake2s256 = blake2.Blake2s256;
+pub const Blake2b384 = blake2.Blake2b384;
+pub const Blake2b512 = blake2.Blake2b512;
+
+const hmac = @import("crypto/hmac.zig");
+pub const HmacMd5 = hmac.HmacMd5;
+pub const HmacSha1 = hmac.HmacSha1;
+pub const HmacSha256 = hmac.HmacSha256;
+pub const HmacBlake2s256 = hmac.HmacBlake2s256;
+
+const import_chaCha20 = @import("crypto/chacha20.zig");
+pub const chaCha20IETF = import_chaCha20.chaCha20IETF;
+pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
+
+pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
+pub const X25519 = @import("crypto/x25519.zig").X25519;
+
+test "crypto" {
+ _ = @import("crypto/blake2.zig");
+ _ = @import("crypto/chacha20.zig");
+ _ = @import("crypto/hmac.zig");
+ _ = @import("crypto/md5.zig");
+ _ = @import("crypto/poly1305.zig");
+ _ = @import("crypto/sha1.zig");
+ _ = @import("crypto/sha2.zig");
+ _ = @import("crypto/sha3.zig");
+ _ = @import("crypto/x25519.zig");
+}
diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig
index e3de65916acc1e17c40d97b1f634cc1de0ae3bfc..e9f617261f562cf7329111bdb10d9fc161fa68ba 100644
--- a/std/crypto/blake2.zig
+++ b/std/crypto/blake2.zig
@@ -1,7 +1,7 @@
const mem = @import("../mem.zig");
-const math = @import("../math/index.zig");
+const math = @import("../math.zig");
const endian = @import("../endian.zig");
-const debug = @import("../debug/index.zig");
+const debug = @import("../debug.zig");
const builtin = @import("builtin");
const htest = @import("test.zig");
@@ -34,8 +34,8 @@ pub const Blake2s256 = Blake2s(256);
fn Blake2s(comptime out_len: usize) type {
return struct {
const Self = @This();
- const block_length = 64;
- const digest_length = out_len / 8;
+ pub const block_length = 64;
+ pub const digest_length = out_len / 8;
const iv = [8]u32{
0x6A09E667,
diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig
index d964f4c03d023c93d0647c2e5da1766c7c5d24a6..78ef700bdfe029af9590f78c05e61d80c81acd8b 100644
--- a/std/crypto/chacha20.zig
+++ b/std/crypto/chacha20.zig
@@ -1,6 +1,6 @@
// Based on public domain Supercop by Daniel J. Bernstein
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const mem = std.mem;
const endian = std.endian;
const assert = std.debug.assert;
diff --git a/std/crypto/hmac.zig b/std/crypto/hmac.zig
index 51dda1b1ea2e8f5dde3b27d8e0cc8ad09f5f6a2e..69c1b86386cb362fd5c58b0e5eb32b2814d1dcad 100644
--- a/std/crypto/hmac.zig
+++ b/std/crypto/hmac.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const crypto = std.crypto;
const debug = std.debug;
const mem = std.mem;
diff --git a/std/crypto/index.zig b/std/crypto/index.zig
deleted file mode 100644
index 3855bd8dd37135e626cadbc2b241ab554d7b36bb..0000000000000000000000000000000000000000
--- a/std/crypto/index.zig
+++ /dev/null
@@ -1,45 +0,0 @@
-pub const Md5 = @import("md5.zig").Md5;
-pub const Sha1 = @import("sha1.zig").Sha1;
-
-const sha2 = @import("sha2.zig");
-pub const Sha224 = sha2.Sha224;
-pub const Sha256 = sha2.Sha256;
-pub const Sha384 = sha2.Sha384;
-pub const Sha512 = sha2.Sha512;
-
-const sha3 = @import("sha3.zig");
-pub const Sha3_224 = sha3.Sha3_224;
-pub const Sha3_256 = sha3.Sha3_256;
-pub const Sha3_384 = sha3.Sha3_384;
-pub const Sha3_512 = sha3.Sha3_512;
-
-const blake2 = @import("blake2.zig");
-pub const Blake2s224 = blake2.Blake2s224;
-pub const Blake2s256 = blake2.Blake2s256;
-pub const Blake2b384 = blake2.Blake2b384;
-pub const Blake2b512 = blake2.Blake2b512;
-
-const hmac = @import("hmac.zig");
-pub const HmacMd5 = hmac.HmacMd5;
-pub const HmacSha1 = hmac.HmacSha1;
-pub const HmacSha256 = hmac.HmacSha256;
-pub const HmacBlake2s256 = hmac.HmacBlake2s256;
-
-const import_chaCha20 = @import("chacha20.zig");
-pub const chaCha20IETF = import_chaCha20.chaCha20IETF;
-pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
-
-pub const Poly1305 = @import("poly1305.zig").Poly1305;
-pub const X25519 = @import("x25519.zig").X25519;
-
-test "crypto" {
- _ = @import("blake2.zig");
- _ = @import("chacha20.zig");
- _ = @import("hmac.zig");
- _ = @import("md5.zig");
- _ = @import("poly1305.zig");
- _ = @import("sha1.zig");
- _ = @import("sha2.zig");
- _ = @import("sha3.zig");
- _ = @import("x25519.zig");
-}
diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig
index 994a7fa25ca3640891a9eb60d69ee9f5bb0aa7bb..d27a3c1c337eb143fc0c8db5e829d92a49c14620 100644
--- a/std/crypto/md5.zig
+++ b/std/crypto/md5.zig
@@ -1,9 +1,9 @@
const mem = @import("../mem.zig");
-const math = @import("../math/index.zig");
+const math = @import("../math.zig");
const endian = @import("../endian.zig");
const builtin = @import("builtin");
-const debug = @import("../debug/index.zig");
-const fmt = @import("../fmt/index.zig");
+const debug = @import("../debug.zig");
+const fmt = @import("../fmt.zig");
const RoundParam = struct {
a: usize,
@@ -29,8 +29,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
pub const Md5 = struct {
const Self = @This();
- const block_length = 64;
- const digest_length = 16;
+ pub const block_length = 64;
+ pub const digest_length = 16;
s: [4]u32,
// Streaming Cache
diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig
index 64adb17c454a46b1c8e3017fac4c6f51c5e0f635..bd0b33e5860b0f85518a0fe1f5ce3ec3210208c2 100644
--- a/std/crypto/poly1305.zig
+++ b/std/crypto/poly1305.zig
@@ -2,7 +2,7 @@
//
// https://monocypher.org/
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const Endian = builtin.Endian;
diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig
index d5aab8f33f776381d0f4a7581e1d8ab6a87fd63e..ee5c118b134eaa212fcf4f38abb5fba375404c06 100644
--- a/std/crypto/sha1.zig
+++ b/std/crypto/sha1.zig
@@ -1,7 +1,7 @@
const mem = @import("../mem.zig");
-const math = @import("../math/index.zig");
+const math = @import("../math.zig");
const endian = @import("../endian.zig");
-const debug = @import("../debug/index.zig");
+const debug = @import("../debug.zig");
const builtin = @import("builtin");
const RoundParam = struct {
@@ -26,8 +26,8 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
pub const Sha1 = struct {
const Self = @This();
- const block_length = 64;
- const digest_length = 20;
+ pub const block_length = 64;
+ pub const digest_length = 20;
s: [5]u32,
// Streaming Cache
diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig
index 0476a3a25e73762bafbfd63f977cdeb1db6a2c26..37b0b65dc62475f38a31db533b6058354cbfda00 100644
--- a/std/crypto/sha2.zig
+++ b/std/crypto/sha2.zig
@@ -1,7 +1,7 @@
const mem = @import("../mem.zig");
-const math = @import("../math/index.zig");
+const math = @import("../math.zig");
const endian = @import("../endian.zig");
-const debug = @import("../debug/index.zig");
+const debug = @import("../debug.zig");
const builtin = @import("builtin");
const htest = @import("test.zig");
@@ -78,8 +78,8 @@ pub const Sha256 = Sha2_32(Sha256Params);
fn Sha2_32(comptime params: Sha2Params32) type {
return struct {
const Self = @This();
- const block_length = 64;
- const digest_length = params.out_len / 8;
+ pub const block_length = 64;
+ pub const digest_length = params.out_len / 8;
s: [8]u32,
// Streaming Cache
diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig
index e686e1337ce1104abae3b8cfb1169728d09e9c8e..beebb3e65d433383a05ed309fcfa5912e734e769 100644
--- a/std/crypto/sha3.zig
+++ b/std/crypto/sha3.zig
@@ -1,7 +1,7 @@
const mem = @import("../mem.zig");
-const math = @import("../math/index.zig");
+const math = @import("../math.zig");
const endian = @import("../endian.zig");
-const debug = @import("../debug/index.zig");
+const debug = @import("../debug.zig");
const builtin = @import("builtin");
const htest = @import("test.zig");
@@ -13,8 +13,8 @@ pub const Sha3_512 = Keccak(512, 0x06);
fn Keccak(comptime bits: usize, comptime delim: u8) type {
return struct {
const Self = @This();
- const block_length = 200;
- const digest_length = bits / 8;
+ pub const block_length = 200;
+ pub const digest_length = bits / 8;
s: [200]u8,
offset: usize,
diff --git a/std/crypto/test.zig b/std/crypto/test.zig
index 258cdf7320580d5feabbdb8b110eb5057ba4924b..a0ddad6c83136bb9890b0f6d6df09ef95d134a1c 100644
--- a/std/crypto/test.zig
+++ b/std/crypto/test.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const testing = std.testing;
const mem = std.mem;
const fmt = std.fmt;
diff --git a/std/crypto/throughput_test.zig b/std/crypto/throughput_test.zig
index 10ef1bcd486682d9e6951344d54e2b1e6b08c0c7..73a2a86124699822409fd5edd113487d5e94a87d 100644
--- a/std/crypto/throughput_test.zig
+++ b/std/crypto/throughput_test.zig
@@ -2,7 +2,7 @@ const builtin = @import("builtin");
const std = @import("std");
const time = std.os.time;
const Timer = time.Timer;
-const crypto = @import("index.zig");
+const crypto = @import("../crypto.zig");
const KiB = 1024;
const MiB = 1024 * KiB;
diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig
index 9349569f97aa271c8ebc970442926fdc2cdc79d7..5d5d31267d54eb84710dc4540a8fc1c74f01f995 100644
--- a/std/crypto/x25519.zig
+++ b/std/crypto/x25519.zig
@@ -2,7 +2,7 @@
//
// https://monocypher.org/
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const fmt = std.fmt;
diff --git a/std/cstr.zig b/std/cstr.zig
index abd2eac48fc8fe7ac80b922a626c91d5b77ee5f0..49d63737325cec4dc8eebb13d9c273fe04f5febb 100644
--- a/std/cstr.zig
+++ b/std/cstr.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const debug = std.debug;
const mem = std.mem;
diff --git a/std/debug.zig b/std/debug.zig
new file mode 100644
index 0000000000000000000000000000000000000000..df35a8e773257d20deb7ac0b7c28a523ca8a5287
--- /dev/null
+++ b/std/debug.zig
@@ -0,0 +1,2205 @@
+const std = @import("std.zig");
+const math = std.math;
+const mem = std.mem;
+const io = std.io;
+const os = std.os;
+const elf = std.elf;
+const DW = std.dwarf;
+const macho = std.macho;
+const coff = std.coff;
+const pdb = std.pdb;
+const windows = os.windows;
+const ArrayList = std.ArrayList;
+const builtin = @import("builtin");
+const maxInt = std.math.maxInt;
+
+pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator;
+pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
+
+pub const runtime_safety = switch (builtin.mode) {
+ builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
+ builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
+};
+
+const Module = struct {
+ mod_info: pdb.ModInfo,
+ module_name: []u8,
+ obj_file_name: []u8,
+
+ populated: bool,
+ symbols: []u8,
+ subsect_info: []u8,
+ checksum_offset: ?usize,
+};
+
+/// Tries to write to stderr, unbuffered, and ignores any error returned.
+/// Does not append a newline.
+var stderr_file: os.File = undefined;
+var stderr_file_out_stream: os.File.OutStream = undefined;
+
+var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
+var stderr_mutex = std.Mutex.init();
+pub fn warn(comptime fmt: []const u8, args: ...) void {
+ const held = stderr_mutex.acquire();
+ defer held.release();
+ const stderr = getStderrStream() catch return;
+ stderr.print(fmt, args) catch return;
+}
+
+pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {
+ if (stderr_stream) |st| {
+ return st;
+ } else {
+ stderr_file = try io.getStdErr();
+ stderr_file_out_stream = stderr_file.outStream();
+ const st = &stderr_file_out_stream.stream;
+ stderr_stream = st;
+ return st;
+ }
+}
+
+/// TODO multithreaded awareness
+var self_debug_info: ?DebugInfo = null;
+
+pub fn getSelfDebugInfo() !*DebugInfo {
+ if (self_debug_info) |*info| {
+ return info;
+ } else {
+ self_debug_info = try openSelfDebugInfo(getDebugInfoAllocator());
+ return &self_debug_info.?;
+ }
+}
+
+fn wantTtyColor() bool {
+ var bytes: [128]u8 = undefined;
+ const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
+ return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
+}
+
+/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
+/// TODO multithreaded awareness
+pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
+ const stderr = getStderrStream() catch return;
+ const debug_info = getSelfDebugInfo() catch |err| {
+ stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
+ return;
+ };
+ writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
+ stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
+ return;
+ };
+}
+
+/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
+/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
+/// and then try to find the first address. If addresses.len is more than 32, we
+/// capture that many stack frames exactly, and then look for the first address,
+/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
+/// equals the passed in addresses pointer.
+pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
+ switch (builtin.os) {
+ builtin.Os.windows => {
+ const addrs = stack_trace.instruction_addresses;
+ const u32_addrs_len = @intCast(u32, addrs.len);
+ const first_addr = first_address orelse {
+ stack_trace.index = windows.RtlCaptureStackBackTrace(
+ 0,
+ u32_addrs_len,
+ @ptrCast(**c_void, addrs.ptr),
+ null,
+ );
+ return;
+ };
+ var addr_buf_stack: [32]usize = undefined;
+ const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
+ const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
+ const first_index = for (addr_buf[0..n]) |addr, i| {
+ if (addr == first_addr) {
+ break i;
+ }
+ } else {
+ stack_trace.index = 0;
+ return;
+ };
+ const slice = addr_buf[first_index..n];
+ // We use a for loop here because slice and addrs may alias.
+ for (slice) |addr, i| {
+ addrs[i] = addr;
+ }
+ stack_trace.index = slice.len;
+ },
+ else => {
+ var it = StackIterator.init(first_address);
+ for (stack_trace.instruction_addresses) |*addr, i| {
+ addr.* = it.next() orelse {
+ stack_trace.index = i;
+ return;
+ };
+ }
+ stack_trace.index = stack_trace.instruction_addresses.len;
+ },
+ }
+}
+
+/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
+/// TODO multithreaded awareness
+pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
+ const stderr = getStderrStream() catch return;
+ const debug_info = getSelfDebugInfo() catch |err| {
+ stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
+ return;
+ };
+ writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
+ stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
+ return;
+ };
+}
+
+/// This function invokes undefined behavior when `ok` is `false`.
+/// In Debug and ReleaseSafe modes, calls to this function are always
+/// generated, and the `unreachable` statement triggers a panic.
+/// In ReleaseFast and ReleaseSmall modes, calls to this function are
+/// optimized away, and in fact the optimizer is able to use the assertion
+/// in its heuristics.
+/// Inside a test block, it is best to use the `std.testing` module rather
+/// than this function, because this function may not detect a test failure
+/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert
+/// function is the correct function to use.
+pub fn assert(ok: bool) void {
+ if (!ok) unreachable; // assertion failure
+}
+
+pub fn panic(comptime format: []const u8, args: ...) noreturn {
+ @setCold(true);
+ const first_trace_addr = @returnAddress();
+ panicExtra(null, first_trace_addr, format, args);
+}
+
+/// TODO multithreaded awareness
+var panicking: u8 = 0; // TODO make this a bool
+
+pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
+ @setCold(true);
+
+ if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
+ // Panicked during a panic.
+
+ // TODO detect if a different thread caused the panic, because in that case
+ // we would want to return here instead of calling abort, so that the thread
+ // which first called panic can finish printing a stack trace.
+ os.abort();
+ }
+ const stderr = getStderrStream() catch os.abort();
+ stderr.print(format ++ "\n", args) catch os.abort();
+ if (trace) |t| {
+ dumpStackTrace(t.*);
+ }
+ dumpCurrentStackTrace(first_trace_addr);
+
+ os.abort();
+}
+
+const RED = "\x1b[31;1m";
+const GREEN = "\x1b[32;1m";
+const CYAN = "\x1b[36;1m";
+const WHITE = "\x1b[37;1m";
+const DIM = "\x1b[2m";
+const RESET = "\x1b[0m";
+
+pub fn writeStackTrace(
+ stack_trace: builtin.StackTrace,
+ out_stream: var,
+ allocator: *mem.Allocator,
+ debug_info: *DebugInfo,
+ tty_color: bool,
+) !void {
+ var frame_index: usize = 0;
+ var frames_left: usize = stack_trace.index;
+
+ while (frames_left != 0) : ({
+ frames_left -= 1;
+ frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
+ }) {
+ const return_address = stack_trace.instruction_addresses[frame_index];
+ try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
+ }
+}
+
+pub const StackIterator = struct {
+ first_addr: ?usize,
+ fp: usize,
+
+ pub fn init(first_addr: ?usize) StackIterator {
+ return StackIterator{
+ .first_addr = first_addr,
+ .fp = @frameAddress(),
+ };
+ }
+
+ fn next(self: *StackIterator) ?usize {
+ if (self.fp == 0) return null;
+ self.fp = @intToPtr(*const usize, self.fp).*;
+ if (self.fp == 0) return null;
+
+ if (self.first_addr) |addr| {
+ while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
+ const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
+ if (addr == return_address) {
+ self.first_addr = null;
+ return return_address;
+ }
+ }
+ }
+
+ const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
+ return return_address;
+ }
+};
+
+pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
+ switch (builtin.os) {
+ builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
+ else => {},
+ }
+ var it = StackIterator.init(start_addr);
+ while (it.next()) |return_address| {
+ try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
+ }
+}
+
+pub fn writeCurrentStackTraceWindows(
+ out_stream: var,
+ debug_info: *DebugInfo,
+ tty_color: bool,
+ start_addr: ?usize,
+) !void {
+ var addr_buf: [1024]usize = undefined;
+ const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
+ const addrs = addr_buf[0..n];
+ var start_i: usize = if (start_addr) |saddr| blk: {
+ for (addrs) |addr, i| {
+ if (addr == saddr) break :blk i;
+ }
+ return;
+ } else 0;
+ for (addrs[start_i..]) |addr| {
+ try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
+ }
+}
+
+pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+ switch (builtin.os) {
+ builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
+ builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
+ else => return error.UnsupportedOperatingSystem,
+ }
+}
+
+fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
+ const allocator = getDebugInfoAllocator();
+ const base_address = os.getBaseAddress();
+ const relative_address = relocated_address - base_address;
+
+ var coff_section: *coff.Section = undefined;
+ const mod_index = for (di.sect_contribs) |sect_contrib| {
+ if (sect_contrib.Section > di.coff.sections.len) continue;
+ // Remember that SectionContribEntry.Section is 1-based.
+ coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
+
+ const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
+ const vaddr_end = vaddr_start + sect_contrib.Size;
+ if (relative_address >= vaddr_start and relative_address < vaddr_end) {
+ break sect_contrib.ModuleIndex;
+ }
+ } else {
+ // we have no information to add to the address
+ if (tty_color) {
+ try out_stream.print("???:?:?: ");
+ setTtyColor(TtyColor.Dim);
+ try out_stream.print("0x{x} in ??? (???)", relocated_address);
+ setTtyColor(TtyColor.Reset);
+ try out_stream.print("\n\n\n");
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
+ }
+ return;
+ };
+
+ const mod = &di.modules[mod_index];
+ try populateModule(di, mod);
+ const obj_basename = os.path.basename(mod.obj_file_name);
+
+ var symbol_i: usize = 0;
+ const symbol_name = while (symbol_i != mod.symbols.len) {
+ const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
+ if (prefix.RecordLen < 2)
+ return error.InvalidDebugInfo;
+ switch (prefix.RecordKind) {
+ pdb.SymbolKind.S_LPROC32 => {
+ const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
+ const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
+ const vaddr_end = vaddr_start + proc_sym.CodeSize;
+ if (relative_address >= vaddr_start and relative_address < vaddr_end) {
+ break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
+ }
+ },
+ else => {},
+ }
+ symbol_i += prefix.RecordLen + @sizeOf(u16);
+ if (symbol_i > mod.symbols.len)
+ return error.InvalidDebugInfo;
+ } else "???";
+
+ const subsect_info = mod.subsect_info;
+
+ var sect_offset: usize = 0;
+ var skip_len: usize = undefined;
+ const opt_line_info = subsections: {
+ const checksum_offset = mod.checksum_offset orelse break :subsections null;
+ while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
+ const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
+ skip_len = subsect_hdr.Length;
+ sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
+
+ switch (subsect_hdr.Kind) {
+ pdb.DebugSubsectionKind.Lines => {
+ var line_index = sect_offset;
+
+ const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
+ if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
+ line_index += @sizeOf(pdb.LineFragmentHeader);
+ const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
+ const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
+
+ // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
+ // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
+ // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
+ const subsection_end_index = sect_offset + subsect_hdr.Length;
+ while (line_index < subsection_end_index) {
+ const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
+ line_index += @sizeOf(pdb.LineBlockFragmentHeader);
+ const start_line_index = line_index;
+
+ const has_column = line_hdr.Flags.LF_HaveColumns;
+
+ if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
+ // All line entries are stored inside their line block by ascending start address.
+ // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
+ // This is done with a simple linear search.
+ var line_i: u32 = 0;
+ while (line_i < block_hdr.NumLines) : (line_i += 1) {
+ const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
+ line_index += @sizeOf(pdb.LineNumberEntry);
+
+ const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
+ if (relative_address <= vaddr_start) {
+ break;
+ }
+ }
+
+ // line_i == 0 would mean that no matching LineNumberEntry was found.
+ if (line_i > 0) {
+ const subsect_index = checksum_offset + block_hdr.NameIndex;
+ const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
+ const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
+ try di.pdb.string_table.seekTo(strtab_offset);
+ const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
+
+ const line_entry_idx = line_i - 1;
+
+ const column = if (has_column) blk: {
+ const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
+ const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
+ const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
+ break :blk col_num_entry.StartColumn;
+ } else 0;
+
+ const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
+ const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
+ const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
+
+ break :subsections LineInfo{
+ .allocator = allocator,
+ .file_name = source_file_name,
+ .line = flags.Start,
+ .column = column,
+ };
+ }
+ }
+ }
+
+ // Checking that we are not reading garbage after the (possibly) multiple block fragments.
+ if (line_index != subsection_end_index) {
+ return error.InvalidDebugInfo;
+ }
+ },
+ else => {},
+ }
+
+ if (sect_offset > subsect_info.len)
+ return error.InvalidDebugInfo;
+ } else {
+ break :subsections null;
+ }
+ };
+
+ if (tty_color) {
+ setTtyColor(TtyColor.White);
+ if (opt_line_info) |li| {
+ try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
+ } else {
+ try out_stream.print("???:?:?");
+ }
+ setTtyColor(TtyColor.Reset);
+ try out_stream.print(": ");
+ setTtyColor(TtyColor.Dim);
+ try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
+ setTtyColor(TtyColor.Reset);
+
+ if (opt_line_info) |line_info| {
+ try out_stream.print("\n");
+ if (printLineFromFileAnyOs(out_stream, line_info)) {
+ if (line_info.column == 0) {
+ try out_stream.write("\n");
+ } else {
+ {
+ var col_i: usize = 1;
+ while (col_i < line_info.column) : (col_i += 1) {
+ try out_stream.writeByte(' ');
+ }
+ }
+ setTtyColor(TtyColor.Green);
+ try out_stream.write("^");
+ setTtyColor(TtyColor.Reset);
+ try out_stream.write("\n");
+ }
+ } else |err| switch (err) {
+ error.EndOfFile => {},
+ else => return err,
+ }
+ } else {
+ try out_stream.print("\n\n\n");
+ }
+ } else {
+ if (opt_line_info) |li| {
+ try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
+ }
+ }
+}
+
+const TtyColor = enum {
+ Red,
+ Green,
+ Cyan,
+ White,
+ Dim,
+ Bold,
+ Reset,
+};
+
+/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
+fn setTtyColor(tty_color: TtyColor) void {
+ if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {
+ switch (tty_color) {
+ TtyColor.Red => {
+ stderr_file.write(RED) catch return;
+ },
+ TtyColor.Green => {
+ stderr_file.write(GREEN) catch return;
+ },
+ TtyColor.Cyan => {
+ stderr_file.write(CYAN) catch return;
+ },
+ TtyColor.White, TtyColor.Bold => {
+ stderr_file.write(WHITE) catch return;
+ },
+ TtyColor.Dim => {
+ stderr_file.write(DIM) catch return;
+ },
+ TtyColor.Reset => {
+ stderr_file.write(RESET) catch return;
+ },
+ }
+ } else {
+ const S = struct {
+ var attrs: windows.WORD = undefined;
+ var init_attrs = false;
+ };
+ if (!S.init_attrs) {
+ S.init_attrs = true;
+ var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
+ // TODO handle error
+ _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
+ S.attrs = info.wAttributes;
+ }
+
+ // TODO handle errors
+ switch (tty_color) {
+ TtyColor.Red => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Green => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Cyan => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.White, TtyColor.Bold => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Dim => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
+ },
+ TtyColor.Reset => {
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
+ },
+ }
+ }
+}
+
+fn populateModule(di: *DebugInfo, mod: *Module) !void {
+ if (mod.populated)
+ return;
+ const allocator = getDebugInfoAllocator();
+
+ if (mod.mod_info.C11ByteSize != 0)
+ return error.InvalidDebugInfo;
+
+ if (mod.mod_info.C13ByteSize == 0)
+ return error.MissingDebugInfo;
+
+ const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
+
+ const signature = try modi.stream.readIntLittle(u32);
+ if (signature != 4)
+ return error.InvalidDebugInfo;
+
+ mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
+ try modi.stream.readNoEof(mod.symbols);
+
+ mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
+ try modi.stream.readNoEof(mod.subsect_info);
+
+ var sect_offset: usize = 0;
+ var skip_len: usize = undefined;
+ while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
+ const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
+ skip_len = subsect_hdr.Length;
+ sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
+
+ switch (subsect_hdr.Kind) {
+ pdb.DebugSubsectionKind.FileChecksums => {
+ mod.checksum_offset = sect_offset;
+ break;
+ },
+ else => {},
+ }
+
+ if (sect_offset > mod.subsect_info.len)
+ return error.InvalidDebugInfo;
+ }
+
+ mod.populated = true;
+}
+
+fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
+ var min: usize = 0;
+ var max: usize = symbols.len - 1; // Exclude sentinel.
+ while (min < max) {
+ const mid = min + (max - min) / 2;
+ const curr = &symbols[mid];
+ const next = &symbols[mid + 1];
+ if (address >= next.address()) {
+ min = mid + 1;
+ } else if (address < curr.address()) {
+ max = mid;
+ } else {
+ return curr;
+ }
+ }
+ return null;
+}
+
+fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+ const base_addr = std.os.getBaseAddress();
+ const adjusted_addr = 0x100000000 + (address - base_addr);
+
+ const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
+ if (tty_color) {
+ try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
+ }
+ return;
+ };
+
+ const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
+ const compile_unit_name = if (symbol.ofile) |ofile| blk: {
+ const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
+ break :blk os.path.basename(ofile_path);
+ } else "???";
+ if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
+ defer line_info.deinit();
+ try printLineInfo(
+ out_stream,
+ line_info,
+ address,
+ symbol_name,
+ compile_unit_name,
+ tty_color,
+ printLineFromFileAnyOs,
+ );
+ } else |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => {
+ if (tty_color) {
+ try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", address, symbol_name, compile_unit_name);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", address, symbol_name, compile_unit_name);
+ }
+ },
+ else => return err,
+ }
+}
+
+/// This function works in freestanding mode.
+/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
+pub fn printSourceAtAddressDwarf(
+ debug_info: *DwarfInfo,
+ out_stream: var,
+ address: usize,
+ tty_color: bool,
+ comptime printLineFromFile: var,
+) !void {
+ const compile_unit = findCompileUnit(debug_info, address) catch {
+ if (tty_color) {
+ try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
+ }
+ return;
+ };
+ const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
+ if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
+ defer line_info.deinit();
+ const symbol_name = "???";
+ try printLineInfo(
+ out_stream,
+ line_info,
+ address,
+ symbol_name,
+ compile_unit_name,
+ tty_color,
+ printLineFromFile,
+ );
+ } else |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => {
+ if (tty_color) {
+ try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
+ } else {
+ try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
+ }
+ },
+ else => return err,
+ }
+}
+
+pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+ return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
+}
+
+fn printLineInfo(
+ out_stream: var,
+ line_info: LineInfo,
+ address: usize,
+ symbol_name: []const u8,
+ compile_unit_name: []const u8,
+ tty_color: bool,
+ comptime printLineFromFile: var,
+) !void {
+ if (tty_color) {
+ try out_stream.print(
+ WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n",
+ line_info.file_name,
+ line_info.line,
+ line_info.column,
+ address,
+ symbol_name,
+ compile_unit_name,
+ );
+ if (printLineFromFile(out_stream, line_info)) {
+ if (line_info.column == 0) {
+ try out_stream.write("\n");
+ } else {
+ {
+ var col_i: usize = 1;
+ while (col_i < line_info.column) : (col_i += 1) {
+ try out_stream.writeByte(' ');
+ }
+ }
+ try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
+ }
+ } else |err| switch (err) {
+ error.EndOfFile => {},
+ else => return err,
+ }
+ } else {
+ try out_stream.print(
+ "{}:{}:{}: 0x{x} in {} ({})\n",
+ line_info.file_name,
+ line_info.line,
+ line_info.column,
+ address,
+ symbol_name,
+ compile_unit_name,
+ );
+ }
+}
+
+// TODO use this
+pub const OpenSelfDebugInfoError = error{
+ MissingDebugInfo,
+ OutOfMemory,
+ UnsupportedOperatingSystem,
+};
+
+pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
+ switch (builtin.os) {
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
+ builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
+ builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
+ else => return error.UnsupportedOperatingSystem,
+ }
+}
+
+fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
+ const self_file = try os.openSelfExe();
+ defer self_file.close();
+
+ const coff_obj = try allocator.create(coff.Coff);
+ coff_obj.* = coff.Coff{
+ .in_file = self_file,
+ .allocator = allocator,
+ .coff_header = undefined,
+ .pe_header = undefined,
+ .sections = undefined,
+ .guid = undefined,
+ .age = undefined,
+ };
+
+ var di = DebugInfo{
+ .coff = coff_obj,
+ .pdb = undefined,
+ .sect_contribs = undefined,
+ .modules = undefined,
+ };
+
+ try di.coff.loadHeader();
+
+ var path_buf: [windows.MAX_PATH]u8 = undefined;
+ const len = try di.coff.getPdbPath(path_buf[0..]);
+ const raw_path = path_buf[0..len];
+
+ const path = try os.path.resolve(allocator, [][]const u8{raw_path});
+
+ try di.pdb.openFile(di.coff, path);
+
+ var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
+ const version = try pdb_stream.stream.readIntLittle(u32);
+ const signature = try pdb_stream.stream.readIntLittle(u32);
+ const age = try pdb_stream.stream.readIntLittle(u32);
+ var guid: [16]u8 = undefined;
+ try pdb_stream.stream.readNoEof(guid[0..]);
+ if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
+ return error.InvalidDebugInfo;
+ // We validated the executable and pdb match.
+
+ const string_table_index = str_tab_index: {
+ const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
+ const name_bytes = try allocator.alloc(u8, name_bytes_len);
+ try pdb_stream.stream.readNoEof(name_bytes);
+
+ const HashTableHeader = packed struct {
+ Size: u32,
+ Capacity: u32,
+
+ fn maxLoad(cap: u32) u32 {
+ return cap * 2 / 3 + 1;
+ }
+ };
+ const hash_tbl_hdr = try pdb_stream.stream.readStruct(HashTableHeader);
+ if (hash_tbl_hdr.Capacity == 0)
+ return error.InvalidDebugInfo;
+
+ if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
+ return error.InvalidDebugInfo;
+
+ const present = try readSparseBitVector(&pdb_stream.stream, allocator);
+ if (present.len != hash_tbl_hdr.Size)
+ return error.InvalidDebugInfo;
+ const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
+
+ const Bucket = struct {
+ first: u32,
+ second: u32,
+ };
+ const bucket_list = try allocator.alloc(Bucket, present.len);
+ for (present) |_| {
+ const name_offset = try pdb_stream.stream.readIntLittle(u32);
+ const name_index = try pdb_stream.stream.readIntLittle(u32);
+ const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
+ if (mem.eql(u8, name, "/names")) {
+ break :str_tab_index name_index;
+ }
+ }
+ return error.MissingDebugInfo;
+ };
+
+ di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
+ di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
+
+ const dbi = di.pdb.dbi;
+
+ // Dbi Header
+ const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
+ const mod_info_size = dbi_stream_header.ModInfoSize;
+ const section_contrib_size = dbi_stream_header.SectionContributionSize;
+
+ var modules = ArrayList(Module).init(allocator);
+
+ // Module Info Substream
+ var mod_info_offset: usize = 0;
+ while (mod_info_offset != mod_info_size) {
+ const mod_info = try dbi.stream.readStruct(pdb.ModInfo);
+ var this_record_len: usize = @sizeOf(pdb.ModInfo);
+
+ const module_name = try dbi.readNullTermString(allocator);
+ this_record_len += module_name.len + 1;
+
+ const obj_file_name = try dbi.readNullTermString(allocator);
+ this_record_len += obj_file_name.len + 1;
+
+ const march_forward_bytes = this_record_len % 4;
+ if (march_forward_bytes != 0) {
+ try dbi.seekForward(march_forward_bytes);
+ this_record_len += march_forward_bytes;
+ }
+
+ try modules.append(Module{
+ .mod_info = mod_info,
+ .module_name = module_name,
+ .obj_file_name = obj_file_name,
+
+ .populated = false,
+ .symbols = undefined,
+ .subsect_info = undefined,
+ .checksum_offset = null,
+ });
+
+ mod_info_offset += this_record_len;
+ if (mod_info_offset > mod_info_size)
+ return error.InvalidDebugInfo;
+ }
+
+ di.modules = modules.toOwnedSlice();
+
+ // Section Contribution Substream
+ var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
+ var sect_cont_offset: usize = 0;
+ if (section_contrib_size != 0) {
+ const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
+ if (ver != pdb.SectionContrSubstreamVersion.Ver60)
+ return error.InvalidDebugInfo;
+ sect_cont_offset += @sizeOf(u32);
+ }
+ while (sect_cont_offset != section_contrib_size) {
+ const entry = try sect_contribs.addOne();
+ entry.* = try dbi.stream.readStruct(pdb.SectionContribEntry);
+ sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
+
+ if (sect_cont_offset > section_contrib_size)
+ return error.InvalidDebugInfo;
+ }
+
+ di.sect_contribs = sect_contribs.toOwnedSlice();
+
+ return di;
+}
+
+fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
+ const num_words = try stream.readIntLittle(u32);
+ var word_i: usize = 0;
+ var list = ArrayList(usize).init(allocator);
+ while (word_i != num_words) : (word_i += 1) {
+ const word = try stream.readIntLittle(u32);
+ var bit_i: u5 = 0;
+ while (true) : (bit_i += 1) {
+ if (word & (u32(1) << bit_i) != 0) {
+ try list.append(word_i * 32 + bit_i);
+ }
+ if (bit_i == maxInt(u5)) break;
+ }
+ }
+ return list.toOwnedSlice();
+}
+
+fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
+ const elf_header = (try elf_file.findSection(name)) orelse return null;
+ return DwarfInfo.Section{
+ .offset = elf_header.offset,
+ .size = elf_header.size,
+ };
+}
+
+/// Initialize DWARF info. The caller has the responsibility to initialize most
+/// the DwarfInfo fields before calling. These fields can be left undefined:
+/// * abbrev_table_list
+/// * compile_unit_list
+pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
+ di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
+ di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
+ try scanAllCompileUnits(di);
+}
+
+pub fn openElfDebugInfo(
+ allocator: *mem.Allocator,
+ elf_seekable_stream: *DwarfSeekableStream,
+ elf_in_stream: *DwarfInStream,
+) !DwarfInfo {
+ var efile: elf.Elf = undefined;
+ try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
+ errdefer efile.close();
+
+ var di = DwarfInfo{
+ .dwarf_seekable_stream = elf_seekable_stream,
+ .dwarf_in_stream = elf_in_stream,
+ .endian = efile.endian,
+ .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
+ .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
+ .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
+ .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
+ .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
+ .abbrev_table_list = undefined,
+ .compile_unit_list = undefined,
+ };
+ try openDwarfDebugInfo(&di, allocator);
+ return di;
+}
+
+fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
+ const S = struct {
+ var self_exe_file: os.File = undefined;
+ var self_exe_seekable_stream: os.File.SeekableStream = undefined;
+ var self_exe_in_stream: os.File.InStream = undefined;
+ };
+ S.self_exe_file = try os.openSelfExe();
+ errdefer S.self_exe_file.close();
+
+ S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
+ S.self_exe_in_stream = S.self_exe_file.inStream();
+
+ return openElfDebugInfo(
+ allocator,
+ // TODO https://github.com/ziglang/zig/issues/764
+ @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
+ // TODO https://github.com/ziglang/zig/issues/764
+ @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
+ );
+}
+
+fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
+ const hdr = &std.c._mh_execute_header;
+ assert(hdr.magic == std.macho.MH_MAGIC_64);
+
+ const hdr_base = @ptrCast([*]u8, hdr);
+ var ptr = hdr_base + @sizeOf(macho.mach_header_64);
+ var ncmd: u32 = hdr.ncmds;
+ const symtab = while (ncmd != 0) : (ncmd -= 1) {
+ const lc = @ptrCast(*std.macho.load_command, ptr);
+ switch (lc.cmd) {
+ std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr),
+ else => {},
+ }
+ ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
+ } else {
+ return error.MissingDebugInfo;
+ };
+ const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
+ const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];
+
+ const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
+
+ var ofile: ?*macho.nlist_64 = null;
+ var reloc: u64 = 0;
+ var symbol_index: usize = 0;
+ var last_len: u64 = 0;
+ for (syms) |*sym| {
+ if (sym.n_type & std.macho.N_STAB != 0) {
+ switch (sym.n_type) {
+ std.macho.N_OSO => {
+ ofile = sym;
+ reloc = 0;
+ },
+ std.macho.N_FUN => {
+ if (sym.n_sect == 0) {
+ last_len = sym.n_value;
+ } else {
+ symbols_buf[symbol_index] = MachoSymbol{
+ .nlist = sym,
+ .ofile = ofile,
+ .reloc = reloc,
+ };
+ symbol_index += 1;
+ }
+ },
+ std.macho.N_BNSYM => {
+ if (reloc == 0) {
+ reloc = sym.n_value;
+ }
+ },
+ else => continue,
+ }
+ }
+ }
+ const sentinel = try allocator.create(macho.nlist_64);
+ sentinel.* = macho.nlist_64{
+ .n_strx = 0,
+ .n_type = 36,
+ .n_sect = 0,
+ .n_desc = 0,
+ .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len,
+ };
+
+ const symbols = allocator.shrink(MachoSymbol, symbols_buf, symbol_index);
+
+ // Even though lld emits symbols in ascending order, this debug code
+ // should work for programs linked in any valid way.
+ // This sort is so that we can binary search later.
+ std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
+
+ return DebugInfo{
+ .ofiles = DebugInfo.OFileTable.init(allocator),
+ .symbols = symbols,
+ .strings = strings,
+ };
+}
+
+fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
+ var f = try os.File.openRead(line_info.file_name);
+ defer f.close();
+ // TODO fstat and make sure that the file has the correct size
+
+ var buf: [os.page_size]u8 = undefined;
+ var line: usize = 1;
+ var column: usize = 1;
+ var abs_index: usize = 0;
+ while (true) {
+ const amt_read = try f.read(buf[0..]);
+ const slice = buf[0..amt_read];
+
+ for (slice) |byte| {
+ if (line == line_info.line) {
+ try out_stream.writeByte(byte);
+ if (byte == '\n') {
+ return;
+ }
+ }
+ if (byte == '\n') {
+ line += 1;
+ column = 1;
+ } else {
+ column += 1;
+ }
+ }
+
+ if (amt_read < buf.len) return error.EndOfFile;
+ }
+}
+
+const MachoSymbol = struct {
+ nlist: *macho.nlist_64,
+ ofile: ?*macho.nlist_64,
+ reloc: u64,
+
+ /// Returns the address from the macho file
+ fn address(self: MachoSymbol) u64 {
+ return self.nlist.n_value;
+ }
+
+ fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool {
+ return lhs.address() < rhs.address();
+ }
+};
+
+const MachOFile = struct {
+ bytes: []align(@alignOf(macho.mach_header_64)) const u8,
+ sect_debug_info: ?*const macho.section_64,
+ sect_debug_line: ?*const macho.section_64,
+};
+
+pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
+pub const DwarfInStream = io.InStream(anyerror);
+
+pub const DwarfInfo = struct {
+ dwarf_seekable_stream: *DwarfSeekableStream,
+ dwarf_in_stream: *DwarfInStream,
+ endian: builtin.Endian,
+ debug_info: Section,
+ debug_abbrev: Section,
+ debug_str: Section,
+ debug_line: Section,
+ debug_ranges: ?Section,
+ abbrev_table_list: ArrayList(AbbrevTableHeader),
+ compile_unit_list: ArrayList(CompileUnit),
+
+ pub const Section = struct {
+ offset: usize,
+ size: usize,
+ };
+
+ pub fn allocator(self: DwarfInfo) *mem.Allocator {
+ return self.abbrev_table_list.allocator;
+ }
+
+ pub fn readString(self: *DwarfInfo) ![]u8 {
+ return readStringRaw(self.allocator(), self.dwarf_in_stream);
+ }
+};
+
+pub const DebugInfo = switch (builtin.os) {
+ builtin.Os.macosx => struct {
+ symbols: []const MachoSymbol,
+ strings: []const u8,
+ ofiles: OFileTable,
+
+ const OFileTable = std.HashMap(
+ *macho.nlist_64,
+ MachOFile,
+ std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
+ std.hash_map.getTrivialEqlFn(*macho.nlist_64),
+ );
+
+ pub fn allocator(self: DebugInfo) *mem.Allocator {
+ return self.ofiles.allocator;
+ }
+ },
+ builtin.Os.uefi, builtin.Os.windows => struct {
+ pdb: pdb.Pdb,
+ coff: *coff.Coff,
+ sect_contribs: []pdb.SectionContribEntry,
+ modules: []Module,
+ },
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
+ else => @compileError("Unsupported OS"),
+};
+
+const PcRange = struct {
+ start: u64,
+ end: u64,
+};
+
+const CompileUnit = struct {
+ version: u16,
+ is_64: bool,
+ die: *Die,
+ index: usize,
+ pc_range: ?PcRange,
+};
+
+const AbbrevTable = ArrayList(AbbrevTableEntry);
+
+const AbbrevTableHeader = struct {
+ // offset from .debug_abbrev
+ offset: u64,
+ table: AbbrevTable,
+};
+
+const AbbrevTableEntry = struct {
+ has_children: bool,
+ abbrev_code: u64,
+ tag_id: u64,
+ attrs: ArrayList(AbbrevAttr),
+};
+
+const AbbrevAttr = struct {
+ attr_id: u64,
+ form_id: u64,
+};
+
+const FormValue = union(enum) {
+ Address: u64,
+ Block: []u8,
+ Const: Constant,
+ ExprLoc: []u8,
+ Flag: bool,
+ SecOffset: u64,
+ Ref: []u8,
+ RefAddr: u64,
+ RefSig8: u64,
+ String: []u8,
+ StrPtr: u64,
+};
+
+const Constant = struct {
+ payload: []u8,
+ signed: bool,
+
+ fn asUnsignedLe(self: *const Constant) !u64 {
+ if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
+ if (self.signed) return error.InvalidDebugInfo;
+ return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
+ }
+};
+
+const Die = struct {
+ tag_id: u64,
+ has_children: bool,
+ attrs: ArrayList(Attr),
+
+ const Attr = struct {
+ id: u64,
+ value: FormValue,
+ };
+
+ fn getAttr(self: *const Die, id: u64) ?*const FormValue {
+ for (self.attrs.toSliceConst()) |*attr| {
+ if (attr.id == id) return &attr.value;
+ }
+ return null;
+ }
+
+ fn getAttrAddr(self: *const Die, id: u64) !u64 {
+ const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
+ return switch (form_value.*) {
+ FormValue.Address => |value| value,
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
+ const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
+ return switch (form_value.*) {
+ FormValue.Const => |value| value.asUnsignedLe(),
+ FormValue.SecOffset => |value| value,
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
+ const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
+ return switch (form_value.*) {
+ FormValue.Const => |value| value.asUnsignedLe(),
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
+ const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
+ return switch (form_value.*) {
+ FormValue.String => |value| value,
+ FormValue.StrPtr => |offset| getString(di, offset),
+ else => error.InvalidDebugInfo,
+ };
+ }
+};
+
+const FileEntry = struct {
+ file_name: []const u8,
+ dir_index: usize,
+ mtime: usize,
+ len_bytes: usize,
+};
+
+pub const LineInfo = struct {
+ line: usize,
+ column: usize,
+ file_name: []const u8,
+ allocator: ?*mem.Allocator,
+
+ fn deinit(self: LineInfo) void {
+ const allocator = self.allocator orelse return;
+ allocator.free(self.file_name);
+ }
+};
+
+const LineNumberProgram = struct {
+ address: usize,
+ file: usize,
+ line: isize,
+ column: usize,
+ is_stmt: bool,
+ basic_block: bool,
+ end_sequence: bool,
+
+ target_address: usize,
+ include_dirs: []const []const u8,
+ file_entries: *ArrayList(FileEntry),
+
+ prev_address: usize,
+ prev_file: usize,
+ prev_line: isize,
+ prev_column: usize,
+ prev_is_stmt: bool,
+ prev_basic_block: bool,
+ prev_end_sequence: bool,
+
+ pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
+ return LineNumberProgram{
+ .address = 0,
+ .file = 1,
+ .line = 1,
+ .column = 0,
+ .is_stmt = is_stmt,
+ .basic_block = false,
+ .end_sequence = false,
+ .include_dirs = include_dirs,
+ .file_entries = file_entries,
+ .target_address = target_address,
+ .prev_address = 0,
+ .prev_file = undefined,
+ .prev_line = undefined,
+ .prev_column = undefined,
+ .prev_is_stmt = undefined,
+ .prev_basic_block = undefined,
+ .prev_end_sequence = undefined,
+ };
+ }
+
+ pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
+ if (self.target_address >= self.prev_address and self.target_address < self.address) {
+ const file_entry = if (self.prev_file == 0) {
+ return error.MissingDebugInfo;
+ } else if (self.prev_file - 1 >= self.file_entries.len) {
+ return error.InvalidDebugInfo;
+ } else
+ &self.file_entries.items[self.prev_file - 1];
+
+ const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
+ return error.InvalidDebugInfo;
+ } else
+ self.include_dirs[file_entry.dir_index];
+ const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
+ errdefer self.file_entries.allocator.free(file_name);
+ return LineInfo{
+ .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
+ .column = self.prev_column,
+ .file_name = file_name,
+ .allocator = self.file_entries.allocator,
+ };
+ }
+
+ self.prev_address = self.address;
+ self.prev_file = self.file;
+ self.prev_line = self.line;
+ self.prev_column = self.column;
+ self.prev_is_stmt = self.is_stmt;
+ self.prev_basic_block = self.basic_block;
+ self.prev_end_sequence = self.end_sequence;
+ return null;
+ }
+};
+
+fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
+ var buf = ArrayList(u8).init(allocator);
+ while (true) {
+ const byte = try in_stream.readByte();
+ if (byte == 0) break;
+ try buf.append(byte);
+ }
+ return buf.toSlice();
+}
+
+fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
+ const pos = di.debug_str.offset + offset;
+ try di.dwarf_seekable_stream.seekTo(pos);
+ return di.readString();
+}
+
+fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
+ const buf = try allocator.alloc(u8, size);
+ errdefer allocator.free(buf);
+ if ((try in_stream.read(buf)) < size) return error.EndOfFile;
+ return buf;
+}
+
+fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
+ const buf = try readAllocBytes(allocator, in_stream, size);
+ return FormValue{ .Block = buf };
+}
+
+fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
+ const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
+ return parseFormValueBlockLen(allocator, in_stream, block_len);
+}
+
+fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
+ return FormValue{
+ .Const = Constant{
+ .signed = signed,
+ .payload = try readAllocBytes(allocator, in_stream, size),
+ },
+ };
+}
+
+fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
+ return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
+}
+
+fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
+ return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
+}
+
+fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
+ const buf = try readAllocBytes(allocator, in_stream, size);
+ return FormValue{ .Ref = buf };
+}
+
+fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
+ const block_len = try in_stream.readIntLittle(T);
+ return parseFormValueRefLen(allocator, in_stream, block_len);
+}
+
+fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
+ return switch (form_id) {
+ DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
+ DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
+ DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
+ DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
+ DW.FORM_block => x: {
+ const block_len = try readULeb128(in_stream);
+ return parseFormValueBlockLen(allocator, in_stream, block_len);
+ },
+ DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
+ DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
+ DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
+ DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
+ DW.FORM_udata, DW.FORM_sdata => {
+ const block_len = try readULeb128(in_stream);
+ const signed = form_id == DW.FORM_sdata;
+ return parseFormValueConstant(allocator, in_stream, signed, block_len);
+ },
+ DW.FORM_exprloc => {
+ const size = try readULeb128(in_stream);
+ const buf = try readAllocBytes(allocator, in_stream, size);
+ return FormValue{ .ExprLoc = buf };
+ },
+ DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
+ DW.FORM_flag_present => FormValue{ .Flag = true },
+ DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
+
+ DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
+ DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
+ DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
+ DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
+ DW.FORM_ref_udata => {
+ const ref_len = try readULeb128(in_stream);
+ return parseFormValueRefLen(allocator, in_stream, ref_len);
+ },
+
+ DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
+
+ DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
+ DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_indirect => {
+ const child_form_id = try readULeb128(in_stream);
+ return parseFormValue(allocator, in_stream, child_form_id, is_64);
+ },
+ else => error.InvalidDebugInfo,
+ };
+}
+
+fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
+ var result = AbbrevTable.init(di.allocator());
+ while (true) {
+ const abbrev_code = try readULeb128(di.dwarf_in_stream);
+ if (abbrev_code == 0) return result;
+ try result.append(AbbrevTableEntry{
+ .abbrev_code = abbrev_code,
+ .tag_id = try readULeb128(di.dwarf_in_stream),
+ .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
+ .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
+ });
+ const attrs = &result.items[result.len - 1].attrs;
+
+ while (true) {
+ const attr_id = try readULeb128(di.dwarf_in_stream);
+ const form_id = try readULeb128(di.dwarf_in_stream);
+ if (attr_id == 0 and form_id == 0) break;
+ try attrs.append(AbbrevAttr{
+ .attr_id = attr_id,
+ .form_id = form_id,
+ });
+ }
+ }
+}
+
+/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
+/// seeks in the stream and parses it.
+fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
+ for (di.abbrev_table_list.toSlice()) |*header| {
+ if (header.offset == abbrev_offset) {
+ return &header.table;
+ }
+ }
+ try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
+ try di.abbrev_table_list.append(AbbrevTableHeader{
+ .offset = abbrev_offset,
+ .table = try parseAbbrevTable(di),
+ });
+ return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
+}
+
+fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
+ for (abbrev_table.toSliceConst()) |*table_entry| {
+ if (table_entry.abbrev_code == abbrev_code) return table_entry;
+ }
+ return null;
+}
+
+fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
+ const abbrev_code = try readULeb128(di.dwarf_in_stream);
+ const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
+
+ var result = Die{
+ .tag_id = table_entry.tag_id,
+ .has_children = table_entry.has_children,
+ .attrs = ArrayList(Die.Attr).init(di.allocator()),
+ };
+ try result.attrs.resize(table_entry.attrs.len);
+ for (table_entry.attrs.toSliceConst()) |attr, i| {
+ result.attrs.items[i] = Die.Attr{
+ .id = attr.attr_id,
+ .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
+ };
+ }
+ return result;
+}
+
+fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
+ const ofile = symbol.ofile orelse return error.MissingDebugInfo;
+ const gop = try di.ofiles.getOrPut(ofile);
+ const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
+ errdefer _ = di.ofiles.remove(ofile);
+ const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
+
+ gop.kv.value = MachOFile{
+ .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)),
+ .sect_debug_info = null,
+ .sect_debug_line = null,
+ };
+ const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr);
+ if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
+
+ const hdr_base = @ptrCast([*]const u8, hdr);
+ var ptr = hdr_base + @sizeOf(macho.mach_header_64);
+ var ncmd: u32 = hdr.ncmds;
+ const segcmd = while (ncmd != 0) : (ncmd -= 1) {
+ const lc = @ptrCast(*const std.macho.load_command, ptr);
+ switch (lc.cmd) {
+ std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
+ else => {},
+ }
+ ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
+ } else {
+ return error.MissingDebugInfo;
+ };
+ const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
+ for (sections) |*sect| {
+ if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
+ (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
+ {
+ const sect_name = mem.toSliceConst(u8, §.sectname);
+ if (mem.eql(u8, sect_name, "__debug_line")) {
+ gop.kv.value.sect_debug_line = sect;
+ } else if (mem.eql(u8, sect_name, "__debug_info")) {
+ gop.kv.value.sect_debug_info = sect;
+ }
+ }
+ }
+
+ break :blk &gop.kv.value;
+ };
+
+ const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo;
+ var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset;
+
+ var is_64: bool = undefined;
+ const unit_length = try readInitialLengthMem(&ptr, &is_64);
+ if (unit_length == 0) return error.MissingDebugInfo;
+
+ const version = readIntMem(&ptr, u16, builtin.Endian.Little);
+ // TODO support 3 and 5
+ if (version != 2 and version != 4) return error.InvalidDebugInfo;
+
+ const prologue_length = if (is_64)
+ readIntMem(&ptr, u64, builtin.Endian.Little)
+ else
+ readIntMem(&ptr, u32, builtin.Endian.Little);
+ const prog_start = ptr + prologue_length;
+
+ const minimum_instruction_length = readByteMem(&ptr);
+ if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+
+ if (version >= 4) {
+ // maximum_operations_per_instruction
+ ptr += 1;
+ }
+
+ const default_is_stmt = readByteMem(&ptr) != 0;
+ const line_base = readByteSignedMem(&ptr);
+
+ const line_range = readByteMem(&ptr);
+ if (line_range == 0) return error.InvalidDebugInfo;
+
+ const opcode_base = readByteMem(&ptr);
+
+ const standard_opcode_lengths = ptr[0 .. opcode_base - 1];
+ ptr += opcode_base - 1;
+
+ var include_directories = ArrayList([]const u8).init(di.allocator());
+ try include_directories.append("");
+ while (true) {
+ const dir = readStringMem(&ptr);
+ if (dir.len == 0) break;
+ try include_directories.append(dir);
+ }
+
+ var file_entries = ArrayList(FileEntry).init(di.allocator());
+ var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
+
+ while (true) {
+ const file_name = readStringMem(&ptr);
+ if (file_name.len == 0) break;
+ const dir_index = try readULeb128Mem(&ptr);
+ const mtime = try readULeb128Mem(&ptr);
+ const len_bytes = try readULeb128Mem(&ptr);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ }
+
+ ptr = prog_start;
+ while (true) {
+ const opcode = readByteMem(&ptr);
+
+ if (opcode == DW.LNS_extended_op) {
+ const op_size = try readULeb128Mem(&ptr);
+ if (op_size < 1) return error.InvalidDebugInfo;
+ var sub_op = readByteMem(&ptr);
+ switch (sub_op) {
+ DW.LNE_end_sequence => {
+ prog.end_sequence = true;
+ if (try prog.checkLineMatch()) |info| return info;
+ return error.MissingDebugInfo;
+ },
+ DW.LNE_set_address => {
+ const addr = readIntMem(&ptr, usize, builtin.Endian.Little);
+ prog.address = symbol.reloc + addr;
+ },
+ DW.LNE_define_file => {
+ const file_name = readStringMem(&ptr);
+ const dir_index = try readULeb128Mem(&ptr);
+ const mtime = try readULeb128Mem(&ptr);
+ const len_bytes = try readULeb128Mem(&ptr);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ },
+ else => {
+ ptr += op_size - 1;
+ },
+ }
+ } else if (opcode >= opcode_base) {
+ // special opcodes
+ const adjusted_opcode = opcode - opcode_base;
+ const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
+ const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
+ prog.line += inc_line;
+ prog.address += inc_addr;
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ } else {
+ switch (opcode) {
+ DW.LNS_copy => {
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ },
+ DW.LNS_advance_pc => {
+ const arg = try readULeb128Mem(&ptr);
+ prog.address += arg * minimum_instruction_length;
+ },
+ DW.LNS_advance_line => {
+ const arg = try readILeb128Mem(&ptr);
+ prog.line += arg;
+ },
+ DW.LNS_set_file => {
+ const arg = try readULeb128Mem(&ptr);
+ prog.file = arg;
+ },
+ DW.LNS_set_column => {
+ const arg = try readULeb128Mem(&ptr);
+ prog.column = arg;
+ },
+ DW.LNS_negate_stmt => {
+ prog.is_stmt = !prog.is_stmt;
+ },
+ DW.LNS_set_basic_block => {
+ prog.basic_block = true;
+ },
+ DW.LNS_const_add_pc => {
+ const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
+ prog.address += inc_addr;
+ },
+ DW.LNS_fixed_advance_pc => {
+ const arg = readIntMem(&ptr, u16, builtin.Endian.Little);
+ prog.address += arg;
+ },
+ DW.LNS_set_prologue_end => {},
+ else => {
+ if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
+ const len_bytes = standard_opcode_lengths[opcode - 1];
+ ptr += len_bytes;
+ },
+ }
+ }
+ }
+
+ return error.MissingDebugInfo;
+}
+
+fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
+ const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
+
+ const debug_line_end = di.debug_line.offset + di.debug_line.size;
+ var this_offset = di.debug_line.offset;
+ var this_index: usize = 0;
+
+ while (this_offset < debug_line_end) : (this_index += 1) {
+ try di.dwarf_seekable_stream.seekTo(this_offset);
+
+ var is_64: bool = undefined;
+ const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
+ if (unit_length == 0) return error.MissingDebugInfo;
+ const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
+
+ if (compile_unit.index != this_index) {
+ this_offset += next_offset;
+ continue;
+ }
+
+ const version = try di.dwarf_in_stream.readInt(u16, di.endian);
+ // TODO support 3 and 5
+ if (version != 2 and version != 4) return error.InvalidDebugInfo;
+
+ 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);
+ const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
+
+ const minimum_instruction_length = try di.dwarf_in_stream.readByte();
+ if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+
+ if (version >= 4) {
+ // maximum_operations_per_instruction
+ _ = try di.dwarf_in_stream.readByte();
+ }
+
+ const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
+ const line_base = try di.dwarf_in_stream.readByteSigned();
+
+ const line_range = try di.dwarf_in_stream.readByte();
+ if (line_range == 0) return error.InvalidDebugInfo;
+
+ const opcode_base = try di.dwarf_in_stream.readByte();
+
+ const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
+
+ {
+ var i: usize = 0;
+ while (i < opcode_base - 1) : (i += 1) {
+ standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
+ }
+ }
+
+ var include_directories = ArrayList([]u8).init(di.allocator());
+ try include_directories.append(compile_unit_cwd);
+ while (true) {
+ const dir = try di.readString();
+ if (dir.len == 0) break;
+ try include_directories.append(dir);
+ }
+
+ var file_entries = ArrayList(FileEntry).init(di.allocator());
+ var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
+
+ while (true) {
+ const file_name = try di.readString();
+ if (file_name.len == 0) break;
+ const dir_index = try readULeb128(di.dwarf_in_stream);
+ const mtime = try readULeb128(di.dwarf_in_stream);
+ const len_bytes = try readULeb128(di.dwarf_in_stream);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ }
+
+ try di.dwarf_seekable_stream.seekTo(prog_start_offset);
+
+ while (true) {
+ const opcode = try di.dwarf_in_stream.readByte();
+
+ if (opcode == DW.LNS_extended_op) {
+ const op_size = try readULeb128(di.dwarf_in_stream);
+ if (op_size < 1) return error.InvalidDebugInfo;
+ var sub_op = try di.dwarf_in_stream.readByte();
+ switch (sub_op) {
+ DW.LNE_end_sequence => {
+ prog.end_sequence = true;
+ if (try prog.checkLineMatch()) |info| return info;
+ return error.MissingDebugInfo;
+ },
+ DW.LNE_set_address => {
+ const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
+ prog.address = addr;
+ },
+ DW.LNE_define_file => {
+ const file_name = try di.readString();
+ const dir_index = try readULeb128(di.dwarf_in_stream);
+ const mtime = try readULeb128(di.dwarf_in_stream);
+ const len_bytes = try readULeb128(di.dwarf_in_stream);
+ try file_entries.append(FileEntry{
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ },
+ else => {
+ const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
+ try di.dwarf_seekable_stream.seekForward(fwd_amt);
+ },
+ }
+ } else if (opcode >= opcode_base) {
+ // special opcodes
+ const adjusted_opcode = opcode - opcode_base;
+ const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
+ const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
+ prog.line += inc_line;
+ prog.address += inc_addr;
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ } else {
+ switch (opcode) {
+ DW.LNS_copy => {
+ if (try prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ },
+ DW.LNS_advance_pc => {
+ const arg = try readULeb128(di.dwarf_in_stream);
+ prog.address += arg * minimum_instruction_length;
+ },
+ DW.LNS_advance_line => {
+ const arg = try readILeb128(di.dwarf_in_stream);
+ prog.line += arg;
+ },
+ DW.LNS_set_file => {
+ const arg = try readULeb128(di.dwarf_in_stream);
+ prog.file = arg;
+ },
+ DW.LNS_set_column => {
+ const arg = try readULeb128(di.dwarf_in_stream);
+ prog.column = arg;
+ },
+ DW.LNS_negate_stmt => {
+ prog.is_stmt = !prog.is_stmt;
+ },
+ DW.LNS_set_basic_block => {
+ prog.basic_block = true;
+ },
+ DW.LNS_const_add_pc => {
+ const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
+ prog.address += inc_addr;
+ },
+ DW.LNS_fixed_advance_pc => {
+ const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
+ prog.address += arg;
+ },
+ DW.LNS_set_prologue_end => {},
+ else => {
+ if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
+ const len_bytes = standard_opcode_lengths[opcode - 1];
+ try di.dwarf_seekable_stream.seekForward(len_bytes);
+ },
+ }
+ }
+ }
+
+ this_offset += next_offset;
+ }
+
+ return error.MissingDebugInfo;
+}
+
+fn scanAllCompileUnits(di: *DwarfInfo) !void {
+ const debug_info_end = di.debug_info.offset + di.debug_info.size;
+ var this_unit_offset = di.debug_info.offset;
+ var cu_index: usize = 0;
+
+ while (this_unit_offset < debug_info_end) {
+ try di.dwarf_seekable_stream.seekTo(this_unit_offset);
+
+ var is_64: bool = undefined;
+ const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
+ if (unit_length == 0) return;
+ const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
+
+ const version = try di.dwarf_in_stream.readInt(u16, di.endian);
+ if (version < 2 or version > 5) return error.InvalidDebugInfo;
+
+ 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);
+
+ const address_size = try di.dwarf_in_stream.readByte();
+ if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
+
+ const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
+ const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
+
+ try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
+
+ const compile_unit_die = try di.allocator().create(Die);
+ compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
+
+ if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
+
+ const pc_range = x: {
+ if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
+ if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
+ const pc_end = switch (high_pc_value.*) {
+ FormValue.Address => |value| value,
+ FormValue.Const => |value| b: {
+ const offset = try value.asUnsignedLe();
+ break :b (low_pc + offset);
+ },
+ else => return error.InvalidDebugInfo,
+ };
+ break :x PcRange{
+ .start = low_pc,
+ .end = pc_end,
+ };
+ } else {
+ break :x null;
+ }
+ } else |err| {
+ if (err != error.MissingDebugInfo) return err;
+ break :x null;
+ }
+ };
+
+ try di.compile_unit_list.append(CompileUnit{
+ .version = version,
+ .is_64 = is_64,
+ .pc_range = pc_range,
+ .die = compile_unit_die,
+ .index = cu_index,
+ });
+
+ this_unit_offset += next_offset;
+ cu_index += 1;
+ }
+}
+
+fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
+ for (di.compile_unit_list.toSlice()) |*compile_unit| {
+ if (compile_unit.pc_range) |range| {
+ if (target_address >= range.start and target_address < range.end) return compile_unit;
+ }
+ if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
+ var base_address: usize = 0;
+ if (di.debug_ranges) |debug_ranges| {
+ try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
+ while (true) {
+ const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
+ const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
+ if (begin_addr == 0 and end_addr == 0) {
+ break;
+ }
+ if (begin_addr == maxInt(usize)) {
+ base_address = begin_addr;
+ continue;
+ }
+ if (target_address >= begin_addr and target_address < end_addr) {
+ return compile_unit;
+ }
+ }
+ }
+ } else |err| {
+ if (err != error.MissingDebugInfo) return err;
+ continue;
+ }
+ }
+ return error.MissingDebugInfo;
+}
+
+fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
+ // TODO https://github.com/ziglang/zig/issues/863
+ const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
+ ptr.* += @sizeOf(T);
+ return result;
+}
+
+fn readByteMem(ptr: *[*]const u8) u8 {
+ const result = ptr.*[0];
+ ptr.* += 1;
+ return result;
+}
+
+fn readByteSignedMem(ptr: *[*]const u8) i8 {
+ return @bitCast(i8, readByteMem(ptr));
+}
+
+fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
+ // TODO this code can be improved with https://github.com/ziglang/zig/issues/863
+ const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
+ is_64.* = (first_32_bits == 0xffffffff);
+ if (is_64.*) {
+ ptr.* += 4;
+ const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
+ ptr.* += 8;
+ return result;
+ } else {
+ if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
+ ptr.* += 4;
+ return u64(first_32_bits);
+ }
+}
+
+fn readStringMem(ptr: *[*]const u8) []const u8 {
+ const result = mem.toSliceConst(u8, ptr.*);
+ ptr.* += result.len + 1;
+ return result;
+}
+
+fn readULeb128Mem(ptr: *[*]const u8) !u64 {
+ var result: u64 = 0;
+ var shift: usize = 0;
+ var i: usize = 0;
+
+ while (true) {
+ const byte = ptr.*[i];
+ i += 1;
+
+ var operand: u64 = undefined;
+
+ if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
+
+ result |= operand;
+
+ if ((byte & 0b10000000) == 0) {
+ ptr.* += i;
+ return result;
+ }
+
+ shift += 7;
+ }
+}
+fn readILeb128Mem(ptr: *[*]const u8) !i64 {
+ var result: i64 = 0;
+ var shift: usize = 0;
+ var i: usize = 0;
+
+ while (true) {
+ const byte = ptr.*[i];
+ i += 1;
+
+ var operand: i64 = undefined;
+ if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
+
+ result |= operand;
+ shift += 7;
+
+ if ((byte & 0b10000000) == 0) {
+ if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
+ ptr.* += i;
+ return result;
+ }
+ }
+}
+
+fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
+ const first_32_bits = try in_stream.readIntLittle(u32);
+ is_64.* = (first_32_bits == 0xffffffff);
+ if (is_64.*) {
+ return in_stream.readIntLittle(u64);
+ } else {
+ if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
+ return u64(first_32_bits);
+ }
+}
+
+fn readULeb128(in_stream: var) !u64 {
+ var result: u64 = 0;
+ var shift: usize = 0;
+
+ while (true) {
+ const byte = try in_stream.readByte();
+
+ var operand: u64 = undefined;
+
+ if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
+
+ result |= operand;
+
+ if ((byte & 0b10000000) == 0) return result;
+
+ shift += 7;
+ }
+}
+
+fn readILeb128(in_stream: var) !i64 {
+ var result: i64 = 0;
+ var shift: usize = 0;
+
+ while (true) {
+ const byte = try in_stream.readByte();
+
+ var operand: i64 = undefined;
+
+ if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
+
+ result |= operand;
+ shift += 7;
+
+ if ((byte & 0b10000000) == 0) {
+ if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
+ return result;
+ }
+ }
+}
+
+/// This should only be used in temporary test programs.
+pub const global_allocator = &global_fixed_allocator.allocator;
+var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
+var global_allocator_mem: [100 * 1024]u8 = undefined;
+
+/// TODO multithreaded awareness
+var debug_info_allocator: ?*mem.Allocator = null;
+var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
+var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
+fn getDebugInfoAllocator() *mem.Allocator {
+ if (debug_info_allocator) |a| return a;
+
+ debug_info_direct_allocator = std.heap.DirectAllocator.init();
+ debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
+ debug_info_allocator = &debug_info_arena_allocator.allocator;
+ return &debug_info_arena_allocator.allocator;
+}
diff --git a/std/debug/failing_allocator.zig b/std/debug/failing_allocator.zig
index e16dd21db45324ce3c75d92259b96aa8a0f6cce3..82093dffda2f8a0101de2483fe763bafc939d315 100644
--- a/std/debug/failing_allocator.zig
+++ b/std/debug/failing_allocator.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const mem = std.mem;
/// Allocator that fails after N allocations, useful for making sure out of
diff --git a/std/debug/index.zig b/std/debug/index.zig
deleted file mode 100644
index 538fb5ef2807c10464dc7eb9c7635e3cd294e831..0000000000000000000000000000000000000000
--- a/std/debug/index.zig
+++ /dev/null
@@ -1,2205 +0,0 @@
-const std = @import("../index.zig");
-const math = std.math;
-const mem = std.mem;
-const io = std.io;
-const os = std.os;
-const elf = std.elf;
-const DW = std.dwarf;
-const macho = std.macho;
-const coff = std.coff;
-const pdb = std.pdb;
-const windows = os.windows;
-const ArrayList = std.ArrayList;
-const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-
-pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
-pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
-
-pub const runtime_safety = switch (builtin.mode) {
- builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
- builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
-};
-
-const Module = struct {
- mod_info: pdb.ModInfo,
- module_name: []u8,
- obj_file_name: []u8,
-
- populated: bool,
- symbols: []u8,
- subsect_info: []u8,
- checksum_offset: ?usize,
-};
-
-/// Tries to write to stderr, unbuffered, and ignores any error returned.
-/// Does not append a newline.
-var stderr_file: os.File = undefined;
-var stderr_file_out_stream: os.File.OutStream = undefined;
-
-var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
-var stderr_mutex = std.Mutex.init();
-pub fn warn(comptime fmt: []const u8, args: ...) void {
- const held = stderr_mutex.acquire();
- defer held.release();
- const stderr = getStderrStream() catch return;
- stderr.print(fmt, args) catch return;
-}
-
-pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {
- if (stderr_stream) |st| {
- return st;
- } else {
- stderr_file = try io.getStdErr();
- stderr_file_out_stream = stderr_file.outStream();
- const st = &stderr_file_out_stream.stream;
- stderr_stream = st;
- return st;
- }
-}
-
-/// TODO multithreaded awareness
-var self_debug_info: ?DebugInfo = null;
-
-pub fn getSelfDebugInfo() !*DebugInfo {
- if (self_debug_info) |*info| {
- return info;
- } else {
- self_debug_info = try openSelfDebugInfo(getDebugInfoAllocator());
- return &self_debug_info.?;
- }
-}
-
-fn wantTtyColor() bool {
- var bytes: [128]u8 = undefined;
- const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
- return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
-}
-
-/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
-/// TODO multithreaded awareness
-pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
- const stderr = getStderrStream() catch return;
- const debug_info = getSelfDebugInfo() catch |err| {
- stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
- return;
- };
- writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {
- stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
- return;
- };
-}
-
-/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
-/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
-/// and then try to find the first address. If addresses.len is more than 32, we
-/// capture that many stack frames exactly, and then look for the first address,
-/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
-/// equals the passed in addresses pointer.
-pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
- switch (builtin.os) {
- builtin.Os.windows => {
- const addrs = stack_trace.instruction_addresses;
- const u32_addrs_len = @intCast(u32, addrs.len);
- const first_addr = first_address orelse {
- stack_trace.index = windows.RtlCaptureStackBackTrace(
- 0,
- u32_addrs_len,
- @ptrCast(**c_void, addrs.ptr),
- null,
- );
- return;
- };
- var addr_buf_stack: [32]usize = undefined;
- const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
- const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
- const first_index = for (addr_buf[0..n]) |addr, i| {
- if (addr == first_addr) {
- break i;
- }
- } else {
- stack_trace.index = 0;
- return;
- };
- const slice = addr_buf[first_index..n];
- // We use a for loop here because slice and addrs may alias.
- for (slice) |addr, i| {
- addrs[i] = addr;
- }
- stack_trace.index = slice.len;
- },
- else => {
- var it = StackIterator.init(first_address);
- for (stack_trace.instruction_addresses) |*addr, i| {
- addr.* = it.next() orelse {
- stack_trace.index = i;
- return;
- };
- }
- stack_trace.index = stack_trace.instruction_addresses.len;
- },
- }
-}
-
-/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
-/// TODO multithreaded awareness
-pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
- const stderr = getStderrStream() catch return;
- const debug_info = getSelfDebugInfo() catch |err| {
- stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
- return;
- };
- writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {
- stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
- return;
- };
-}
-
-/// This function invokes undefined behavior when `ok` is `false`.
-/// In Debug and ReleaseSafe modes, calls to this function are always
-/// generated, and the `unreachable` statement triggers a panic.
-/// In ReleaseFast and ReleaseSmall modes, calls to this function are
-/// optimized away, and in fact the optimizer is able to use the assertion
-/// in its heuristics.
-/// Inside a test block, it is best to use the `std.testing` module rather
-/// than this function, because this function may not detect a test failure
-/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert
-/// function is the correct function to use.
-pub fn assert(ok: bool) void {
- if (!ok) unreachable; // assertion failure
-}
-
-pub fn panic(comptime format: []const u8, args: ...) noreturn {
- @setCold(true);
- const first_trace_addr = @ptrToInt(@returnAddress());
- panicExtra(null, first_trace_addr, format, args);
-}
-
-/// TODO multithreaded awareness
-var panicking: u8 = 0; // TODO make this a bool
-
-pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
- @setCold(true);
-
- if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
- // Panicked during a panic.
-
- // TODO detect if a different thread caused the panic, because in that case
- // we would want to return here instead of calling abort, so that the thread
- // which first called panic can finish printing a stack trace.
- os.abort();
- }
- const stderr = getStderrStream() catch os.abort();
- stderr.print(format ++ "\n", args) catch os.abort();
- if (trace) |t| {
- dumpStackTrace(t.*);
- }
- dumpCurrentStackTrace(first_trace_addr);
-
- os.abort();
-}
-
-const RED = "\x1b[31;1m";
-const GREEN = "\x1b[32;1m";
-const CYAN = "\x1b[36;1m";
-const WHITE = "\x1b[37;1m";
-const DIM = "\x1b[2m";
-const RESET = "\x1b[0m";
-
-pub fn writeStackTrace(
- stack_trace: builtin.StackTrace,
- out_stream: var,
- allocator: *mem.Allocator,
- debug_info: *DebugInfo,
- tty_color: bool,
-) !void {
- var frame_index: usize = 0;
- var frames_left: usize = stack_trace.index;
-
- while (frames_left != 0) : ({
- frames_left -= 1;
- frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
- }) {
- const return_address = stack_trace.instruction_addresses[frame_index];
- try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
- }
-}
-
-pub const StackIterator = struct {
- first_addr: ?usize,
- fp: usize,
-
- pub fn init(first_addr: ?usize) StackIterator {
- return StackIterator{
- .first_addr = first_addr,
- .fp = @ptrToInt(@frameAddress()),
- };
- }
-
- fn next(self: *StackIterator) ?usize {
- if (self.fp == 0) return null;
- self.fp = @intToPtr(*const usize, self.fp).*;
- if (self.fp == 0) return null;
-
- if (self.first_addr) |addr| {
- while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
- const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
- if (addr == return_address) {
- self.first_addr = null;
- return return_address;
- }
- }
- }
-
- const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
- return return_address;
- }
-};
-
-pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
- switch (builtin.os) {
- builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
- else => {},
- }
- var it = StackIterator.init(start_addr);
- while (it.next()) |return_address| {
- try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
- }
-}
-
-pub fn writeCurrentStackTraceWindows(
- out_stream: var,
- debug_info: *DebugInfo,
- tty_color: bool,
- start_addr: ?usize,
-) !void {
- var addr_buf: [1024]usize = undefined;
- const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
- const addrs = addr_buf[0..n];
- var start_i: usize = if (start_addr) |saddr| blk: {
- for (addrs) |addr, i| {
- if (addr == saddr) break :blk i;
- }
- return;
- } else 0;
- for (addrs[start_i..]) |addr| {
- try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
- }
-}
-
-pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
- switch (builtin.os) {
- builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
- builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
- else => return error.UnsupportedOperatingSystem,
- }
-}
-
-fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
- const allocator = getDebugInfoAllocator();
- const base_address = os.getBaseAddress();
- const relative_address = relocated_address - base_address;
-
- var coff_section: *coff.Section = undefined;
- const mod_index = for (di.sect_contribs) |sect_contrib| {
- if (sect_contrib.Section > di.coff.sections.len) continue;
- // Remember that SectionContribEntry.Section is 1-based.
- coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
-
- const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
- const vaddr_end = vaddr_start + sect_contrib.Size;
- if (relative_address >= vaddr_start and relative_address < vaddr_end) {
- break sect_contrib.ModuleIndex;
- }
- } else {
- // we have no information to add to the address
- if (tty_color) {
- try out_stream.print("???:?:?: ");
- setTtyColor(TtyColor.Dim);
- try out_stream.print("0x{x} in ??? (???)", relocated_address);
- setTtyColor(TtyColor.Reset);
- try out_stream.print("\n\n\n");
- } else {
- try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
- }
- return;
- };
-
- const mod = &di.modules[mod_index];
- try populateModule(di, mod);
- const obj_basename = os.path.basename(mod.obj_file_name);
-
- var symbol_i: usize = 0;
- const symbol_name = while (symbol_i != mod.symbols.len) {
- const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
- if (prefix.RecordLen < 2)
- return error.InvalidDebugInfo;
- switch (prefix.RecordKind) {
- pdb.SymbolKind.S_LPROC32 => {
- const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
- const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
- const vaddr_end = vaddr_start + proc_sym.CodeSize;
- if (relative_address >= vaddr_start and relative_address < vaddr_end) {
- break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
- }
- },
- else => {},
- }
- symbol_i += prefix.RecordLen + @sizeOf(u16);
- if (symbol_i > mod.symbols.len)
- return error.InvalidDebugInfo;
- } else "???";
-
- const subsect_info = mod.subsect_info;
-
- var sect_offset: usize = 0;
- var skip_len: usize = undefined;
- const opt_line_info = subsections: {
- const checksum_offset = mod.checksum_offset orelse break :subsections null;
- while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
- const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
- skip_len = subsect_hdr.Length;
- sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
-
- switch (subsect_hdr.Kind) {
- pdb.DebugSubsectionKind.Lines => {
- var line_index = sect_offset;
-
- const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
- if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
- line_index += @sizeOf(pdb.LineFragmentHeader);
- const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
- const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
-
- // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
- // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
- // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
- const subsection_end_index = sect_offset + subsect_hdr.Length;
- while (line_index < subsection_end_index) {
- const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
- line_index += @sizeOf(pdb.LineBlockFragmentHeader);
- const start_line_index = line_index;
-
- const has_column = line_hdr.Flags.LF_HaveColumns;
-
- if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
- // All line entries are stored inside their line block by ascending start address.
- // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
- // This is done with a simple linear search.
- var line_i: u32 = 0;
- while (line_i < block_hdr.NumLines) : (line_i += 1) {
- const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
- line_index += @sizeOf(pdb.LineNumberEntry);
-
- const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
- if (relative_address <= vaddr_start) {
- break;
- }
- }
-
- // line_i == 0 would mean that no matching LineNumberEntry was found.
- if (line_i > 0) {
- const subsect_index = checksum_offset + block_hdr.NameIndex;
- const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
- const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
- try di.pdb.string_table.seekTo(strtab_offset);
- const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
-
- const line_entry_idx = line_i - 1;
-
- const column = if (has_column) blk: {
- const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
- const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
- const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
- break :blk col_num_entry.StartColumn;
- } else 0;
-
- const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
- const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
- const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
-
- break :subsections LineInfo{
- .allocator = allocator,
- .file_name = source_file_name,
- .line = flags.Start,
- .column = column,
- };
- }
- }
- }
-
- // Checking that we are not reading garbage after the (possibly) multiple block fragments.
- if (line_index != subsection_end_index) {
- return error.InvalidDebugInfo;
- }
- },
- else => {},
- }
-
- if (sect_offset > subsect_info.len)
- return error.InvalidDebugInfo;
- } else {
- break :subsections null;
- }
- };
-
- if (tty_color) {
- setTtyColor(TtyColor.White);
- if (opt_line_info) |li| {
- try out_stream.print("{}:{}:{}", li.file_name, li.line, li.column);
- } else {
- try out_stream.print("???:?:?");
- }
- setTtyColor(TtyColor.Reset);
- try out_stream.print(": ");
- setTtyColor(TtyColor.Dim);
- try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
- setTtyColor(TtyColor.Reset);
-
- if (opt_line_info) |line_info| {
- try out_stream.print("\n");
- if (printLineFromFileAnyOs(out_stream, line_info)) {
- if (line_info.column == 0) {
- try out_stream.write("\n");
- } else {
- {
- var col_i: usize = 1;
- while (col_i < line_info.column) : (col_i += 1) {
- try out_stream.writeByte(' ');
- }
- }
- setTtyColor(TtyColor.Green);
- try out_stream.write("^");
- setTtyColor(TtyColor.Reset);
- try out_stream.write("\n");
- }
- } else |err| switch (err) {
- error.EndOfFile => {},
- else => return err,
- }
- } else {
- try out_stream.print("\n\n\n");
- }
- } else {
- if (opt_line_info) |li| {
- try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
- } else {
- try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
- }
- }
-}
-
-const TtyColor = enum {
- Red,
- Green,
- Cyan,
- White,
- Dim,
- Bold,
- Reset,
-};
-
-/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
-fn setTtyColor(tty_color: TtyColor) void {
- if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {
- switch (tty_color) {
- TtyColor.Red => {
- stderr_file.write(RED) catch return;
- },
- TtyColor.Green => {
- stderr_file.write(GREEN) catch return;
- },
- TtyColor.Cyan => {
- stderr_file.write(CYAN) catch return;
- },
- TtyColor.White, TtyColor.Bold => {
- stderr_file.write(WHITE) catch return;
- },
- TtyColor.Dim => {
- stderr_file.write(DIM) catch return;
- },
- TtyColor.Reset => {
- stderr_file.write(RESET) catch return;
- },
- }
- } else {
- const S = struct {
- var attrs: windows.WORD = undefined;
- var init_attrs = false;
- };
- if (!S.init_attrs) {
- S.init_attrs = true;
- var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
- // TODO handle error
- _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
- S.attrs = info.wAttributes;
- }
-
- // TODO handle errors
- switch (tty_color) {
- TtyColor.Red => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
- },
- TtyColor.Green => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
- },
- TtyColor.Cyan => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
- },
- TtyColor.White, TtyColor.Bold => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
- },
- TtyColor.Dim => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
- },
- TtyColor.Reset => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
- },
- }
- }
-}
-
-fn populateModule(di: *DebugInfo, mod: *Module) !void {
- if (mod.populated)
- return;
- const allocator = getDebugInfoAllocator();
-
- if (mod.mod_info.C11ByteSize != 0)
- return error.InvalidDebugInfo;
-
- if (mod.mod_info.C13ByteSize == 0)
- return error.MissingDebugInfo;
-
- const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
-
- const signature = try modi.stream.readIntLittle(u32);
- if (signature != 4)
- return error.InvalidDebugInfo;
-
- mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
- try modi.stream.readNoEof(mod.symbols);
-
- mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
- try modi.stream.readNoEof(mod.subsect_info);
-
- var sect_offset: usize = 0;
- var skip_len: usize = undefined;
- while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
- const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
- skip_len = subsect_hdr.Length;
- sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
-
- switch (subsect_hdr.Kind) {
- pdb.DebugSubsectionKind.FileChecksums => {
- mod.checksum_offset = sect_offset;
- break;
- },
- else => {},
- }
-
- if (sect_offset > mod.subsect_info.len)
- return error.InvalidDebugInfo;
- }
-
- mod.populated = true;
-}
-
-fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
- var min: usize = 0;
- var max: usize = symbols.len - 1; // Exclude sentinel.
- while (min < max) {
- const mid = min + (max - min) / 2;
- const curr = &symbols[mid];
- const next = &symbols[mid + 1];
- if (address >= next.address()) {
- min = mid + 1;
- } else if (address < curr.address()) {
- max = mid;
- } else {
- return curr;
- }
- }
- return null;
-}
-
-fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
- const base_addr = std.os.getBaseAddress();
- const adjusted_addr = 0x100000000 + (address - base_addr);
-
- const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
- if (tty_color) {
- try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
- } else {
- try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
- }
- return;
- };
-
- const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
- const compile_unit_name = if (symbol.ofile) |ofile| blk: {
- const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
- break :blk os.path.basename(ofile_path);
- } else "???";
- if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
- defer line_info.deinit();
- try printLineInfo(
- out_stream,
- line_info,
- address,
- symbol_name,
- compile_unit_name,
- tty_color,
- printLineFromFileAnyOs,
- );
- } else |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => {
- if (tty_color) {
- try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", address, symbol_name, compile_unit_name);
- } else {
- try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", address, symbol_name, compile_unit_name);
- }
- },
- else => return err,
- }
-}
-
-/// This function works in freestanding mode.
-/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
-pub fn printSourceAtAddressDwarf(
- debug_info: *DwarfInfo,
- out_stream: var,
- address: usize,
- tty_color: bool,
- comptime printLineFromFile: var,
-) !void {
- const compile_unit = findCompileUnit(debug_info, address) catch {
- if (tty_color) {
- try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
- } else {
- try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
- }
- return;
- };
- const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
- if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
- defer line_info.deinit();
- const symbol_name = "???";
- try printLineInfo(
- out_stream,
- line_info,
- address,
- symbol_name,
- compile_unit_name,
- tty_color,
- printLineFromFile,
- );
- } else |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => {
- if (tty_color) {
- try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
- } else {
- try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
- }
- },
- else => return err,
- }
-}
-
-pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
- return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
-}
-
-fn printLineInfo(
- out_stream: var,
- line_info: LineInfo,
- address: usize,
- symbol_name: []const u8,
- compile_unit_name: []const u8,
- tty_color: bool,
- comptime printLineFromFile: var,
-) !void {
- if (tty_color) {
- try out_stream.print(
- WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n",
- line_info.file_name,
- line_info.line,
- line_info.column,
- address,
- symbol_name,
- compile_unit_name,
- );
- if (printLineFromFile(out_stream, line_info)) {
- if (line_info.column == 0) {
- try out_stream.write("\n");
- } else {
- {
- var col_i: usize = 1;
- while (col_i < line_info.column) : (col_i += 1) {
- try out_stream.writeByte(' ');
- }
- }
- try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
- }
- } else |err| switch (err) {
- error.EndOfFile => {},
- else => return err,
- }
- } else {
- try out_stream.print(
- "{}:{}:{}: 0x{x} in {} ({})\n",
- line_info.file_name,
- line_info.line,
- line_info.column,
- address,
- symbol_name,
- compile_unit_name,
- );
- }
-}
-
-// TODO use this
-pub const OpenSelfDebugInfoError = error{
- MissingDebugInfo,
- OutOfMemory,
- UnsupportedOperatingSystem,
-};
-
-pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
- switch (builtin.os) {
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
- builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
- builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
- else => return error.UnsupportedOperatingSystem,
- }
-}
-
-fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
- const self_file = try os.openSelfExe();
- defer self_file.close();
-
- const coff_obj = try allocator.create(coff.Coff);
- coff_obj.* = coff.Coff{
- .in_file = self_file,
- .allocator = allocator,
- .coff_header = undefined,
- .pe_header = undefined,
- .sections = undefined,
- .guid = undefined,
- .age = undefined,
- };
-
- var di = DebugInfo{
- .coff = coff_obj,
- .pdb = undefined,
- .sect_contribs = undefined,
- .modules = undefined,
- };
-
- try di.coff.loadHeader();
-
- var path_buf: [windows.MAX_PATH]u8 = undefined;
- const len = try di.coff.getPdbPath(path_buf[0..]);
- const raw_path = path_buf[0..len];
-
- const path = try os.path.resolve(allocator, [][]const u8{raw_path});
-
- try di.pdb.openFile(di.coff, path);
-
- var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
- const version = try pdb_stream.stream.readIntLittle(u32);
- const signature = try pdb_stream.stream.readIntLittle(u32);
- const age = try pdb_stream.stream.readIntLittle(u32);
- var guid: [16]u8 = undefined;
- try pdb_stream.stream.readNoEof(guid[0..]);
- if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
- return error.InvalidDebugInfo;
- // We validated the executable and pdb match.
-
- const string_table_index = str_tab_index: {
- const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
- const name_bytes = try allocator.alloc(u8, name_bytes_len);
- try pdb_stream.stream.readNoEof(name_bytes);
-
- const HashTableHeader = packed struct {
- Size: u32,
- Capacity: u32,
-
- fn maxLoad(cap: u32) u32 {
- return cap * 2 / 3 + 1;
- }
- };
- const hash_tbl_hdr = try pdb_stream.stream.readStruct(HashTableHeader);
- if (hash_tbl_hdr.Capacity == 0)
- return error.InvalidDebugInfo;
-
- if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
- return error.InvalidDebugInfo;
-
- const present = try readSparseBitVector(&pdb_stream.stream, allocator);
- if (present.len != hash_tbl_hdr.Size)
- return error.InvalidDebugInfo;
- const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
-
- const Bucket = struct {
- first: u32,
- second: u32,
- };
- const bucket_list = try allocator.alloc(Bucket, present.len);
- for (present) |_| {
- const name_offset = try pdb_stream.stream.readIntLittle(u32);
- const name_index = try pdb_stream.stream.readIntLittle(u32);
- const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
- if (mem.eql(u8, name, "/names")) {
- break :str_tab_index name_index;
- }
- }
- return error.MissingDebugInfo;
- };
-
- di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
- di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
-
- const dbi = di.pdb.dbi;
-
- // Dbi Header
- const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
- const mod_info_size = dbi_stream_header.ModInfoSize;
- const section_contrib_size = dbi_stream_header.SectionContributionSize;
-
- var modules = ArrayList(Module).init(allocator);
-
- // Module Info Substream
- var mod_info_offset: usize = 0;
- while (mod_info_offset != mod_info_size) {
- const mod_info = try dbi.stream.readStruct(pdb.ModInfo);
- var this_record_len: usize = @sizeOf(pdb.ModInfo);
-
- const module_name = try dbi.readNullTermString(allocator);
- this_record_len += module_name.len + 1;
-
- const obj_file_name = try dbi.readNullTermString(allocator);
- this_record_len += obj_file_name.len + 1;
-
- const march_forward_bytes = this_record_len % 4;
- if (march_forward_bytes != 0) {
- try dbi.seekForward(march_forward_bytes);
- this_record_len += march_forward_bytes;
- }
-
- try modules.append(Module{
- .mod_info = mod_info,
- .module_name = module_name,
- .obj_file_name = obj_file_name,
-
- .populated = false,
- .symbols = undefined,
- .subsect_info = undefined,
- .checksum_offset = null,
- });
-
- mod_info_offset += this_record_len;
- if (mod_info_offset > mod_info_size)
- return error.InvalidDebugInfo;
- }
-
- di.modules = modules.toOwnedSlice();
-
- // Section Contribution Substream
- var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
- var sect_cont_offset: usize = 0;
- if (section_contrib_size != 0) {
- const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
- if (ver != pdb.SectionContrSubstreamVersion.Ver60)
- return error.InvalidDebugInfo;
- sect_cont_offset += @sizeOf(u32);
- }
- while (sect_cont_offset != section_contrib_size) {
- const entry = try sect_contribs.addOne();
- entry.* = try dbi.stream.readStruct(pdb.SectionContribEntry);
- sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
-
- if (sect_cont_offset > section_contrib_size)
- return error.InvalidDebugInfo;
- }
-
- di.sect_contribs = sect_contribs.toOwnedSlice();
-
- return di;
-}
-
-fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
- const num_words = try stream.readIntLittle(u32);
- var word_i: usize = 0;
- var list = ArrayList(usize).init(allocator);
- while (word_i != num_words) : (word_i += 1) {
- const word = try stream.readIntLittle(u32);
- var bit_i: u5 = 0;
- while (true) : (bit_i += 1) {
- if (word & (u32(1) << bit_i) != 0) {
- try list.append(word_i * 32 + bit_i);
- }
- if (bit_i == maxInt(u5)) break;
- }
- }
- return list.toOwnedSlice();
-}
-
-fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
- const elf_header = (try elf_file.findSection(name)) orelse return null;
- return DwarfInfo.Section{
- .offset = elf_header.offset,
- .size = elf_header.size,
- };
-}
-
-/// Initialize DWARF info. The caller has the responsibility to initialize most
-/// the DwarfInfo fields before calling. These fields can be left undefined:
-/// * abbrev_table_list
-/// * compile_unit_list
-pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
- di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
- di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
- try scanAllCompileUnits(di);
-}
-
-pub fn openElfDebugInfo(
- allocator: *mem.Allocator,
- elf_seekable_stream: *DwarfSeekableStream,
- elf_in_stream: *DwarfInStream,
-) !DwarfInfo {
- var efile: elf.Elf = undefined;
- try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
- errdefer efile.close();
-
- var di = DwarfInfo{
- .dwarf_seekable_stream = elf_seekable_stream,
- .dwarf_in_stream = elf_in_stream,
- .endian = efile.endian,
- .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
- .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
- .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
- .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
- .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
- .abbrev_table_list = undefined,
- .compile_unit_list = undefined,
- };
- try openDwarfDebugInfo(&di, allocator);
- return di;
-}
-
-fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
- const S = struct {
- var self_exe_file: os.File = undefined;
- var self_exe_seekable_stream: os.File.SeekableStream = undefined;
- var self_exe_in_stream: os.File.InStream = undefined;
- };
- S.self_exe_file = try os.openSelfExe();
- errdefer S.self_exe_file.close();
-
- S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
- S.self_exe_in_stream = S.self_exe_file.inStream();
-
- return openElfDebugInfo(
- allocator,
- // TODO https://github.com/ziglang/zig/issues/764
- @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
- // TODO https://github.com/ziglang/zig/issues/764
- @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
- );
-}
-
-fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
- const hdr = &std.c._mh_execute_header;
- assert(hdr.magic == std.macho.MH_MAGIC_64);
-
- const hdr_base = @ptrCast([*]u8, hdr);
- var ptr = hdr_base + @sizeOf(macho.mach_header_64);
- var ncmd: u32 = hdr.ncmds;
- const symtab = while (ncmd != 0) : (ncmd -= 1) {
- const lc = @ptrCast(*std.macho.load_command, ptr);
- switch (lc.cmd) {
- std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr),
- else => {},
- }
- ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
- } else {
- return error.MissingDebugInfo;
- };
- const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
- const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];
-
- const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
-
- var ofile: ?*macho.nlist_64 = null;
- var reloc: u64 = 0;
- var symbol_index: usize = 0;
- var last_len: u64 = 0;
- for (syms) |*sym| {
- if (sym.n_type & std.macho.N_STAB != 0) {
- switch (sym.n_type) {
- std.macho.N_OSO => {
- ofile = sym;
- reloc = 0;
- },
- std.macho.N_FUN => {
- if (sym.n_sect == 0) {
- last_len = sym.n_value;
- } else {
- symbols_buf[symbol_index] = MachoSymbol{
- .nlist = sym,
- .ofile = ofile,
- .reloc = reloc,
- };
- symbol_index += 1;
- }
- },
- std.macho.N_BNSYM => {
- if (reloc == 0) {
- reloc = sym.n_value;
- }
- },
- else => continue,
- }
- }
- }
- const sentinel = try allocator.create(macho.nlist_64);
- sentinel.* = macho.nlist_64{
- .n_strx = 0,
- .n_type = 36,
- .n_sect = 0,
- .n_desc = 0,
- .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len,
- };
-
- const symbols = allocator.shrink(MachoSymbol, symbols_buf, symbol_index);
-
- // Even though lld emits symbols in ascending order, this debug code
- // should work for programs linked in any valid way.
- // This sort is so that we can binary search later.
- std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
-
- return DebugInfo{
- .ofiles = DebugInfo.OFileTable.init(allocator),
- .symbols = symbols,
- .strings = strings,
- };
-}
-
-fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
- var f = try os.File.openRead(line_info.file_name);
- defer f.close();
- // TODO fstat and make sure that the file has the correct size
-
- var buf: [os.page_size]u8 = undefined;
- var line: usize = 1;
- var column: usize = 1;
- var abs_index: usize = 0;
- while (true) {
- const amt_read = try f.read(buf[0..]);
- const slice = buf[0..amt_read];
-
- for (slice) |byte| {
- if (line == line_info.line) {
- try out_stream.writeByte(byte);
- if (byte == '\n') {
- return;
- }
- }
- if (byte == '\n') {
- line += 1;
- column = 1;
- } else {
- column += 1;
- }
- }
-
- if (amt_read < buf.len) return error.EndOfFile;
- }
-}
-
-const MachoSymbol = struct {
- nlist: *macho.nlist_64,
- ofile: ?*macho.nlist_64,
- reloc: u64,
-
- /// Returns the address from the macho file
- fn address(self: MachoSymbol) u64 {
- return self.nlist.n_value;
- }
-
- fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool {
- return lhs.address() < rhs.address();
- }
-};
-
-const MachOFile = struct {
- bytes: []align(@alignOf(macho.mach_header_64)) const u8,
- sect_debug_info: ?*const macho.section_64,
- sect_debug_line: ?*const macho.section_64,
-};
-
-pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
-pub const DwarfInStream = io.InStream(anyerror);
-
-pub const DwarfInfo = struct {
- dwarf_seekable_stream: *DwarfSeekableStream,
- dwarf_in_stream: *DwarfInStream,
- endian: builtin.Endian,
- debug_info: Section,
- debug_abbrev: Section,
- debug_str: Section,
- debug_line: Section,
- debug_ranges: ?Section,
- abbrev_table_list: ArrayList(AbbrevTableHeader),
- compile_unit_list: ArrayList(CompileUnit),
-
- pub const Section = struct {
- offset: usize,
- size: usize,
- };
-
- pub fn allocator(self: DwarfInfo) *mem.Allocator {
- return self.abbrev_table_list.allocator;
- }
-
- pub fn readString(self: *DwarfInfo) ![]u8 {
- return readStringRaw(self.allocator(), self.dwarf_in_stream);
- }
-};
-
-pub const DebugInfo = switch (builtin.os) {
- builtin.Os.macosx => struct {
- symbols: []const MachoSymbol,
- strings: []const u8,
- ofiles: OFileTable,
-
- const OFileTable = std.HashMap(
- *macho.nlist_64,
- MachOFile,
- std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
- std.hash_map.getTrivialEqlFn(*macho.nlist_64),
- );
-
- pub fn allocator(self: DebugInfo) *mem.Allocator {
- return self.ofiles.allocator;
- }
- },
- builtin.Os.uefi, builtin.Os.windows => struct {
- pdb: pdb.Pdb,
- coff: *coff.Coff,
- sect_contribs: []pdb.SectionContribEntry,
- modules: []Module,
- },
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
- else => @compileError("Unsupported OS"),
-};
-
-const PcRange = struct {
- start: u64,
- end: u64,
-};
-
-const CompileUnit = struct {
- version: u16,
- is_64: bool,
- die: *Die,
- index: usize,
- pc_range: ?PcRange,
-};
-
-const AbbrevTable = ArrayList(AbbrevTableEntry);
-
-const AbbrevTableHeader = struct {
- // offset from .debug_abbrev
- offset: u64,
- table: AbbrevTable,
-};
-
-const AbbrevTableEntry = struct {
- has_children: bool,
- abbrev_code: u64,
- tag_id: u64,
- attrs: ArrayList(AbbrevAttr),
-};
-
-const AbbrevAttr = struct {
- attr_id: u64,
- form_id: u64,
-};
-
-const FormValue = union(enum) {
- Address: u64,
- Block: []u8,
- Const: Constant,
- ExprLoc: []u8,
- Flag: bool,
- SecOffset: u64,
- Ref: []u8,
- RefAddr: u64,
- RefSig8: u64,
- String: []u8,
- StrPtr: u64,
-};
-
-const Constant = struct {
- payload: []u8,
- signed: bool,
-
- fn asUnsignedLe(self: *const Constant) !u64 {
- if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
- if (self.signed) return error.InvalidDebugInfo;
- return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
- }
-};
-
-const Die = struct {
- tag_id: u64,
- has_children: bool,
- attrs: ArrayList(Attr),
-
- const Attr = struct {
- id: u64,
- value: FormValue,
- };
-
- fn getAttr(self: *const Die, id: u64) ?*const FormValue {
- for (self.attrs.toSliceConst()) |*attr| {
- if (attr.id == id) return &attr.value;
- }
- return null;
- }
-
- fn getAttrAddr(self: *const Die, id: u64) !u64 {
- const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
- return switch (form_value.*) {
- FormValue.Address => |value| value,
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
- const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
- return switch (form_value.*) {
- FormValue.Const => |value| value.asUnsignedLe(),
- FormValue.SecOffset => |value| value,
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
- const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
- return switch (form_value.*) {
- FormValue.Const => |value| value.asUnsignedLe(),
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
- const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
- return switch (form_value.*) {
- FormValue.String => |value| value,
- FormValue.StrPtr => |offset| getString(di, offset),
- else => error.InvalidDebugInfo,
- };
- }
-};
-
-const FileEntry = struct {
- file_name: []const u8,
- dir_index: usize,
- mtime: usize,
- len_bytes: usize,
-};
-
-pub const LineInfo = struct {
- line: usize,
- column: usize,
- file_name: []const u8,
- allocator: ?*mem.Allocator,
-
- fn deinit(self: LineInfo) void {
- const allocator = self.allocator orelse return;
- allocator.free(self.file_name);
- }
-};
-
-const LineNumberProgram = struct {
- address: usize,
- file: usize,
- line: isize,
- column: usize,
- is_stmt: bool,
- basic_block: bool,
- end_sequence: bool,
-
- target_address: usize,
- include_dirs: []const []const u8,
- file_entries: *ArrayList(FileEntry),
-
- prev_address: usize,
- prev_file: usize,
- prev_line: isize,
- prev_column: usize,
- prev_is_stmt: bool,
- prev_basic_block: bool,
- prev_end_sequence: bool,
-
- pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
- return LineNumberProgram{
- .address = 0,
- .file = 1,
- .line = 1,
- .column = 0,
- .is_stmt = is_stmt,
- .basic_block = false,
- .end_sequence = false,
- .include_dirs = include_dirs,
- .file_entries = file_entries,
- .target_address = target_address,
- .prev_address = 0,
- .prev_file = undefined,
- .prev_line = undefined,
- .prev_column = undefined,
- .prev_is_stmt = undefined,
- .prev_basic_block = undefined,
- .prev_end_sequence = undefined,
- };
- }
-
- pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {
- if (self.target_address >= self.prev_address and self.target_address < self.address) {
- const file_entry = if (self.prev_file == 0) {
- return error.MissingDebugInfo;
- } else if (self.prev_file - 1 >= self.file_entries.len) {
- return error.InvalidDebugInfo;
- } else
- &self.file_entries.items[self.prev_file - 1];
-
- const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
- return error.InvalidDebugInfo;
- } else
- self.include_dirs[file_entry.dir_index];
- const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
- errdefer self.file_entries.allocator.free(file_name);
- return LineInfo{
- .line = if (self.prev_line >= 0) @intCast(usize, self.prev_line) else 0,
- .column = self.prev_column,
- .file_name = file_name,
- .allocator = self.file_entries.allocator,
- };
- }
-
- self.prev_address = self.address;
- self.prev_file = self.file;
- self.prev_line = self.line;
- self.prev_column = self.column;
- self.prev_is_stmt = self.is_stmt;
- self.prev_basic_block = self.basic_block;
- self.prev_end_sequence = self.end_sequence;
- return null;
- }
-};
-
-fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
- var buf = ArrayList(u8).init(allocator);
- while (true) {
- const byte = try in_stream.readByte();
- if (byte == 0) break;
- try buf.append(byte);
- }
- return buf.toSlice();
-}
-
-fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
- const pos = di.debug_str.offset + offset;
- try di.dwarf_seekable_stream.seekTo(pos);
- return di.readString();
-}
-
-fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
- const buf = try allocator.alloc(u8, size);
- errdefer allocator.free(buf);
- if ((try in_stream.read(buf)) < size) return error.EndOfFile;
- return buf;
-}
-
-fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
- const buf = try readAllocBytes(allocator, in_stream, size);
- return FormValue{ .Block = buf };
-}
-
-fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
- const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
- return parseFormValueBlockLen(allocator, in_stream, block_len);
-}
-
-fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
- return FormValue{
- .Const = Constant{
- .signed = signed,
- .payload = try readAllocBytes(allocator, in_stream, size),
- },
- };
-}
-
-fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
- return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
-}
-
-fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
- return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
-}
-
-fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
- const buf = try readAllocBytes(allocator, in_stream, size);
- return FormValue{ .Ref = buf };
-}
-
-fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
- const block_len = try in_stream.readIntLittle(T);
- return parseFormValueRefLen(allocator, in_stream, block_len);
-}
-
-fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
- return switch (form_id) {
- DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
- DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
- DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
- DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
- DW.FORM_block => x: {
- const block_len = try readULeb128(in_stream);
- return parseFormValueBlockLen(allocator, in_stream, block_len);
- },
- DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
- DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
- DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
- DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
- DW.FORM_udata, DW.FORM_sdata => {
- const block_len = try readULeb128(in_stream);
- const signed = form_id == DW.FORM_sdata;
- return parseFormValueConstant(allocator, in_stream, signed, block_len);
- },
- DW.FORM_exprloc => {
- const size = try readULeb128(in_stream);
- const buf = try readAllocBytes(allocator, in_stream, size);
- return FormValue{ .ExprLoc = buf };
- },
- DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },
- DW.FORM_flag_present => FormValue{ .Flag = true },
- DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
-
- DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
- DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
- DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
- DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
- DW.FORM_ref_udata => {
- const ref_len = try readULeb128(in_stream);
- return parseFormValueRefLen(allocator, in_stream, ref_len);
- },
-
- DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
-
- DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
- DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_indirect => {
- const child_form_id = try readULeb128(in_stream);
- return parseFormValue(allocator, in_stream, child_form_id, is_64);
- },
- else => error.InvalidDebugInfo,
- };
-}
-
-fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
- var result = AbbrevTable.init(di.allocator());
- while (true) {
- const abbrev_code = try readULeb128(di.dwarf_in_stream);
- if (abbrev_code == 0) return result;
- try result.append(AbbrevTableEntry{
- .abbrev_code = abbrev_code,
- .tag_id = try readULeb128(di.dwarf_in_stream),
- .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
- .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
- });
- const attrs = &result.items[result.len - 1].attrs;
-
- while (true) {
- const attr_id = try readULeb128(di.dwarf_in_stream);
- const form_id = try readULeb128(di.dwarf_in_stream);
- if (attr_id == 0 and form_id == 0) break;
- try attrs.append(AbbrevAttr{
- .attr_id = attr_id,
- .form_id = form_id,
- });
- }
- }
-}
-
-/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
-/// seeks in the stream and parses it.
-fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
- for (di.abbrev_table_list.toSlice()) |*header| {
- if (header.offset == abbrev_offset) {
- return &header.table;
- }
- }
- try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
- try di.abbrev_table_list.append(AbbrevTableHeader{
- .offset = abbrev_offset,
- .table = try parseAbbrevTable(di),
- });
- return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
-}
-
-fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
- for (abbrev_table.toSliceConst()) |*table_entry| {
- if (table_entry.abbrev_code == abbrev_code) return table_entry;
- }
- return null;
-}
-
-fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
- const abbrev_code = try readULeb128(di.dwarf_in_stream);
- const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
-
- var result = Die{
- .tag_id = table_entry.tag_id,
- .has_children = table_entry.has_children,
- .attrs = ArrayList(Die.Attr).init(di.allocator()),
- };
- try result.attrs.resize(table_entry.attrs.len);
- for (table_entry.attrs.toSliceConst()) |attr, i| {
- result.attrs.items[i] = Die.Attr{
- .id = attr.attr_id,
- .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
- };
- }
- return result;
-}
-
-fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
- const ofile = symbol.ofile orelse return error.MissingDebugInfo;
- const gop = try di.ofiles.getOrPut(ofile);
- const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
- errdefer _ = di.ofiles.remove(ofile);
- const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
-
- gop.kv.value = MachOFile{
- .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)),
- .sect_debug_info = null,
- .sect_debug_line = null,
- };
- const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr);
- if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;
-
- const hdr_base = @ptrCast([*]const u8, hdr);
- var ptr = hdr_base + @sizeOf(macho.mach_header_64);
- var ncmd: u32 = hdr.ncmds;
- const segcmd = while (ncmd != 0) : (ncmd -= 1) {
- const lc = @ptrCast(*const std.macho.load_command, ptr);
- switch (lc.cmd) {
- std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
- else => {},
- }
- ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
- } else {
- return error.MissingDebugInfo;
- };
- const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
- for (sections) |*sect| {
- if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
- (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
- {
- const sect_name = mem.toSliceConst(u8, §.sectname);
- if (mem.eql(u8, sect_name, "__debug_line")) {
- gop.kv.value.sect_debug_line = sect;
- } else if (mem.eql(u8, sect_name, "__debug_info")) {
- gop.kv.value.sect_debug_info = sect;
- }
- }
- }
-
- break :blk &gop.kv.value;
- };
-
- const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo;
- var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset;
-
- var is_64: bool = undefined;
- const unit_length = try readInitialLengthMem(&ptr, &is_64);
- if (unit_length == 0) return error.MissingDebugInfo;
-
- const version = readIntMem(&ptr, u16, builtin.Endian.Little);
- // TODO support 3 and 5
- if (version != 2 and version != 4) return error.InvalidDebugInfo;
-
- const prologue_length = if (is_64)
- readIntMem(&ptr, u64, builtin.Endian.Little)
- else
- readIntMem(&ptr, u32, builtin.Endian.Little);
- const prog_start = ptr + prologue_length;
-
- const minimum_instruction_length = readByteMem(&ptr);
- if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
-
- if (version >= 4) {
- // maximum_operations_per_instruction
- ptr += 1;
- }
-
- const default_is_stmt = readByteMem(&ptr) != 0;
- const line_base = readByteSignedMem(&ptr);
-
- const line_range = readByteMem(&ptr);
- if (line_range == 0) return error.InvalidDebugInfo;
-
- const opcode_base = readByteMem(&ptr);
-
- const standard_opcode_lengths = ptr[0 .. opcode_base - 1];
- ptr += opcode_base - 1;
-
- var include_directories = ArrayList([]const u8).init(di.allocator());
- try include_directories.append("");
- while (true) {
- const dir = readStringMem(&ptr);
- if (dir.len == 0) break;
- try include_directories.append(dir);
- }
-
- var file_entries = ArrayList(FileEntry).init(di.allocator());
- var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
-
- while (true) {
- const file_name = readStringMem(&ptr);
- if (file_name.len == 0) break;
- const dir_index = try readULeb128Mem(&ptr);
- const mtime = try readULeb128Mem(&ptr);
- const len_bytes = try readULeb128Mem(&ptr);
- try file_entries.append(FileEntry{
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- }
-
- ptr = prog_start;
- while (true) {
- const opcode = readByteMem(&ptr);
-
- if (opcode == DW.LNS_extended_op) {
- const op_size = try readULeb128Mem(&ptr);
- if (op_size < 1) return error.InvalidDebugInfo;
- var sub_op = readByteMem(&ptr);
- switch (sub_op) {
- DW.LNE_end_sequence => {
- prog.end_sequence = true;
- if (try prog.checkLineMatch()) |info| return info;
- return error.MissingDebugInfo;
- },
- DW.LNE_set_address => {
- const addr = readIntMem(&ptr, usize, builtin.Endian.Little);
- prog.address = symbol.reloc + addr;
- },
- DW.LNE_define_file => {
- const file_name = readStringMem(&ptr);
- const dir_index = try readULeb128Mem(&ptr);
- const mtime = try readULeb128Mem(&ptr);
- const len_bytes = try readULeb128Mem(&ptr);
- try file_entries.append(FileEntry{
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- },
- else => {
- ptr += op_size - 1;
- },
- }
- } else if (opcode >= opcode_base) {
- // special opcodes
- const adjusted_opcode = opcode - opcode_base;
- const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
- const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
- prog.line += inc_line;
- prog.address += inc_addr;
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- } else {
- switch (opcode) {
- DW.LNS_copy => {
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- },
- DW.LNS_advance_pc => {
- const arg = try readULeb128Mem(&ptr);
- prog.address += arg * minimum_instruction_length;
- },
- DW.LNS_advance_line => {
- const arg = try readILeb128Mem(&ptr);
- prog.line += arg;
- },
- DW.LNS_set_file => {
- const arg = try readULeb128Mem(&ptr);
- prog.file = arg;
- },
- DW.LNS_set_column => {
- const arg = try readULeb128Mem(&ptr);
- prog.column = arg;
- },
- DW.LNS_negate_stmt => {
- prog.is_stmt = !prog.is_stmt;
- },
- DW.LNS_set_basic_block => {
- prog.basic_block = true;
- },
- DW.LNS_const_add_pc => {
- const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
- prog.address += inc_addr;
- },
- DW.LNS_fixed_advance_pc => {
- const arg = readIntMem(&ptr, u16, builtin.Endian.Little);
- prog.address += arg;
- },
- DW.LNS_set_prologue_end => {},
- else => {
- if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
- const len_bytes = standard_opcode_lengths[opcode - 1];
- ptr += len_bytes;
- },
- }
- }
- }
-
- return error.MissingDebugInfo;
-}
-
-fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
- const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
-
- const debug_line_end = di.debug_line.offset + di.debug_line.size;
- var this_offset = di.debug_line.offset;
- var this_index: usize = 0;
-
- while (this_offset < debug_line_end) : (this_index += 1) {
- try di.dwarf_seekable_stream.seekTo(this_offset);
-
- var is_64: bool = undefined;
- const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
- if (unit_length == 0) return error.MissingDebugInfo;
- const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
-
- if (compile_unit.index != this_index) {
- this_offset += next_offset;
- continue;
- }
-
- const version = try di.dwarf_in_stream.readInt(u16, di.endian);
- // TODO support 3 and 5
- if (version != 2 and version != 4) return error.InvalidDebugInfo;
-
- 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);
- const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
-
- const minimum_instruction_length = try di.dwarf_in_stream.readByte();
- if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
-
- if (version >= 4) {
- // maximum_operations_per_instruction
- _ = try di.dwarf_in_stream.readByte();
- }
-
- const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
- const line_base = try di.dwarf_in_stream.readByteSigned();
-
- const line_range = try di.dwarf_in_stream.readByte();
- if (line_range == 0) return error.InvalidDebugInfo;
-
- const opcode_base = try di.dwarf_in_stream.readByte();
-
- const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
-
- {
- var i: usize = 0;
- while (i < opcode_base - 1) : (i += 1) {
- standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
- }
- }
-
- var include_directories = ArrayList([]u8).init(di.allocator());
- try include_directories.append(compile_unit_cwd);
- while (true) {
- const dir = try di.readString();
- if (dir.len == 0) break;
- try include_directories.append(dir);
- }
-
- var file_entries = ArrayList(FileEntry).init(di.allocator());
- var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
-
- while (true) {
- const file_name = try di.readString();
- if (file_name.len == 0) break;
- const dir_index = try readULeb128(di.dwarf_in_stream);
- const mtime = try readULeb128(di.dwarf_in_stream);
- const len_bytes = try readULeb128(di.dwarf_in_stream);
- try file_entries.append(FileEntry{
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- }
-
- try di.dwarf_seekable_stream.seekTo(prog_start_offset);
-
- while (true) {
- const opcode = try di.dwarf_in_stream.readByte();
-
- if (opcode == DW.LNS_extended_op) {
- const op_size = try readULeb128(di.dwarf_in_stream);
- if (op_size < 1) return error.InvalidDebugInfo;
- var sub_op = try di.dwarf_in_stream.readByte();
- switch (sub_op) {
- DW.LNE_end_sequence => {
- prog.end_sequence = true;
- if (try prog.checkLineMatch()) |info| return info;
- return error.MissingDebugInfo;
- },
- DW.LNE_set_address => {
- const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
- prog.address = addr;
- },
- DW.LNE_define_file => {
- const file_name = try di.readString();
- const dir_index = try readULeb128(di.dwarf_in_stream);
- const mtime = try readULeb128(di.dwarf_in_stream);
- const len_bytes = try readULeb128(di.dwarf_in_stream);
- try file_entries.append(FileEntry{
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- },
- else => {
- const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
- try di.dwarf_seekable_stream.seekForward(fwd_amt);
- },
- }
- } else if (opcode >= opcode_base) {
- // special opcodes
- const adjusted_opcode = opcode - opcode_base;
- const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
- const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
- prog.line += inc_line;
- prog.address += inc_addr;
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- } else {
- switch (opcode) {
- DW.LNS_copy => {
- if (try prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- },
- DW.LNS_advance_pc => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.address += arg * minimum_instruction_length;
- },
- DW.LNS_advance_line => {
- const arg = try readILeb128(di.dwarf_in_stream);
- prog.line += arg;
- },
- DW.LNS_set_file => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.file = arg;
- },
- DW.LNS_set_column => {
- const arg = try readULeb128(di.dwarf_in_stream);
- prog.column = arg;
- },
- DW.LNS_negate_stmt => {
- prog.is_stmt = !prog.is_stmt;
- },
- DW.LNS_set_basic_block => {
- prog.basic_block = true;
- },
- DW.LNS_const_add_pc => {
- const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
- prog.address += inc_addr;
- },
- DW.LNS_fixed_advance_pc => {
- const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
- prog.address += arg;
- },
- DW.LNS_set_prologue_end => {},
- else => {
- if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
- const len_bytes = standard_opcode_lengths[opcode - 1];
- try di.dwarf_seekable_stream.seekForward(len_bytes);
- },
- }
- }
- }
-
- this_offset += next_offset;
- }
-
- return error.MissingDebugInfo;
-}
-
-fn scanAllCompileUnits(di: *DwarfInfo) !void {
- const debug_info_end = di.debug_info.offset + di.debug_info.size;
- var this_unit_offset = di.debug_info.offset;
- var cu_index: usize = 0;
-
- while (this_unit_offset < debug_info_end) {
- try di.dwarf_seekable_stream.seekTo(this_unit_offset);
-
- var is_64: bool = undefined;
- const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
- if (unit_length == 0) return;
- const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
-
- const version = try di.dwarf_in_stream.readInt(u16, di.endian);
- if (version < 2 or version > 5) return error.InvalidDebugInfo;
-
- 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);
-
- const address_size = try di.dwarf_in_stream.readByte();
- if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
-
- const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
- const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
-
- try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
-
- const compile_unit_die = try di.allocator().create(Die);
- compile_unit_die.* = try parseDie(di, abbrev_table, is_64);
-
- if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
-
- const pc_range = x: {
- if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
- if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
- const pc_end = switch (high_pc_value.*) {
- FormValue.Address => |value| value,
- FormValue.Const => |value| b: {
- const offset = try value.asUnsignedLe();
- break :b (low_pc + offset);
- },
- else => return error.InvalidDebugInfo,
- };
- break :x PcRange{
- .start = low_pc,
- .end = pc_end,
- };
- } else {
- break :x null;
- }
- } else |err| {
- if (err != error.MissingDebugInfo) return err;
- break :x null;
- }
- };
-
- try di.compile_unit_list.append(CompileUnit{
- .version = version,
- .is_64 = is_64,
- .pc_range = pc_range,
- .die = compile_unit_die,
- .index = cu_index,
- });
-
- this_unit_offset += next_offset;
- cu_index += 1;
- }
-}
-
-fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
- for (di.compile_unit_list.toSlice()) |*compile_unit| {
- if (compile_unit.pc_range) |range| {
- if (target_address >= range.start and target_address < range.end) return compile_unit;
- }
- if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
- var base_address: usize = 0;
- if (di.debug_ranges) |debug_ranges| {
- try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
- while (true) {
- const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
- const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
- if (begin_addr == 0 and end_addr == 0) {
- break;
- }
- if (begin_addr == maxInt(usize)) {
- base_address = begin_addr;
- continue;
- }
- if (target_address >= begin_addr and target_address < end_addr) {
- return compile_unit;
- }
- }
- }
- } else |err| {
- if (err != error.MissingDebugInfo) return err;
- continue;
- }
- }
- return error.MissingDebugInfo;
-}
-
-fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
- // TODO https://github.com/ziglang/zig/issues/863
- const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
- ptr.* += @sizeOf(T);
- return result;
-}
-
-fn readByteMem(ptr: *[*]const u8) u8 {
- const result = ptr.*[0];
- ptr.* += 1;
- return result;
-}
-
-fn readByteSignedMem(ptr: *[*]const u8) i8 {
- return @bitCast(i8, readByteMem(ptr));
-}
-
-fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
- // TODO this code can be improved with https://github.com/ziglang/zig/issues/863
- const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
- is_64.* = (first_32_bits == 0xffffffff);
- if (is_64.*) {
- ptr.* += 4;
- const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
- ptr.* += 8;
- return result;
- } else {
- if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
- ptr.* += 4;
- return u64(first_32_bits);
- }
-}
-
-fn readStringMem(ptr: *[*]const u8) []const u8 {
- const result = mem.toSliceConst(u8, ptr.*);
- ptr.* += result.len + 1;
- return result;
-}
-
-fn readULeb128Mem(ptr: *[*]const u8) !u64 {
- var result: u64 = 0;
- var shift: usize = 0;
- var i: usize = 0;
-
- while (true) {
- const byte = ptr.*[i];
- i += 1;
-
- var operand: u64 = undefined;
-
- if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
-
- if ((byte & 0b10000000) == 0) {
- ptr.* += i;
- return result;
- }
-
- shift += 7;
- }
-}
-fn readILeb128Mem(ptr: *[*]const u8) !i64 {
- var result: i64 = 0;
- var shift: usize = 0;
- var i: usize = 0;
-
- while (true) {
- const byte = ptr.*[i];
- i += 1;
-
- var operand: i64 = undefined;
- if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
- shift += 7;
-
- if ((byte & 0b10000000) == 0) {
- if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
- ptr.* += i;
- return result;
- }
- }
-}
-
-fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
- const first_32_bits = try in_stream.readIntLittle(u32);
- is_64.* = (first_32_bits == 0xffffffff);
- if (is_64.*) {
- return in_stream.readIntLittle(u64);
- } else {
- if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
- return u64(first_32_bits);
- }
-}
-
-fn readULeb128(in_stream: var) !u64 {
- var result: u64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = try in_stream.readByte();
-
- var operand: u64 = undefined;
-
- if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
-
- if ((byte & 0b10000000) == 0) return result;
-
- shift += 7;
- }
-}
-
-fn readILeb128(in_stream: var) !i64 {
- var result: i64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = try in_stream.readByte();
-
- var operand: i64 = undefined;
-
- if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
-
- result |= operand;
- shift += 7;
-
- if ((byte & 0b10000000) == 0) {
- if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift));
- return result;
- }
- }
-}
-
-/// This should only be used in temporary test programs.
-pub const global_allocator = &global_fixed_allocator.allocator;
-var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
-var global_allocator_mem: [100 * 1024]u8 = undefined;
-
-/// TODO multithreaded awareness
-var debug_info_allocator: ?*mem.Allocator = null;
-var debug_info_direct_allocator: std.heap.DirectAllocator = undefined;
-var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
-fn getDebugInfoAllocator() *mem.Allocator {
- if (debug_info_allocator) |a| return a;
-
- debug_info_direct_allocator = std.heap.DirectAllocator.init();
- debug_info_arena_allocator = std.heap.ArenaAllocator.init(&debug_info_direct_allocator.allocator);
- debug_info_allocator = &debug_info_arena_allocator.allocator;
- return &debug_info_arena_allocator.allocator;
-}
diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig
index 66026b1f29005e12039f449a8b20fcc3d6449622..698b0eb21652558224e6ea4988efb304c1d36612 100644
--- a/std/dynamic_library.zig
+++ b/std/dynamic_library.zig
@@ -1,7 +1,7 @@
const builtin = @import("builtin");
const Os = builtin.Os;
-const std = @import("index.zig");
+const std = @import("std.zig");
const mem = std.mem;
const cstr = std.cstr;
const os = std.os;
diff --git a/std/elf.zig b/std/elf.zig
index 6a564c3283fdb022f5ad189bd4dd551b2171bbd1..d0ec5fb2ae14d7c78ba965cbd94e82bad0233a07 100644
--- a/std/elf.zig
+++ b/std/elf.zig
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
-const std = @import("index.zig");
+const std = @import("std.zig");
const io = std.io;
const os = std.os;
const math = std.math;
diff --git a/std/event/channel.zig b/std/event/channel.zig
index 4af9bf612b6b2337455015072743cfa119ad79ab..be5af497740245eb6e9becd274fd68b56222c62b 100644
--- a/std/event/channel.zig
+++ b/std/event/channel.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/event/fs.zig b/std/event/fs.zig
index 653594557396aa8b073c054394f20b97a9694472..b923651b1b918e7fcc00d758acaabc8b200d8eee 100644
--- a/std/event/fs.zig
+++ b/std/event/fs.zig
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const event = std.event;
const assert = std.debug.assert;
const testing = std.testing;
@@ -404,11 +404,7 @@ pub async fn openPosix(
pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
switch (builtin.os) {
- builtin.Os.macosx,
- builtin.Os.linux,
- builtin.Os.freebsd,
- builtin.Os.netbsd
- => {
+ builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
},
@@ -876,10 +872,7 @@ pub fn Watch(comptime V: type) type {
pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
switch (builtin.os) {
- builtin.Os.macosx,
- builtin.Os.freebsd,
- builtin.Os.netbsd
- => return await (async addFileKEvent(self, file_path, value) catch unreachable),
+ builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
else => @compileError("Unsupported OS"),
diff --git a/std/event/future.zig b/std/event/future.zig
index 66acac5ad7376ec1595aa8e7cb45d94ed3138798..0e1b9288986d9efd52d36c5400fe9c054e9fd6b6 100644
--- a/std/event/future.zig
+++ b/std/event/future.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const builtin = @import("builtin");
diff --git a/std/event/group.zig b/std/event/group.zig
index 25e79640cb1d4ad1ec93828ca7279dde2cdd8726..455d1bd60cf9f3226688794aa8ff0b73d5a5ba9f 100644
--- a/std/event/group.zig
+++ b/std/event/group.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const Lock = std.event.Lock;
const Loop = std.event.Loop;
diff --git a/std/event/io.zig b/std/event/io.zig
index b11550f7aa6fa328d29ef64b61fab15ee8f751cc..29419a792e995435e3f6dc2539ac3597c3afc076 100644
--- a/std/event/io.zig
+++ b/std/event/io.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
diff --git a/std/event/lock.zig b/std/event/lock.zig
index d6a246cee5340d31ce751f885166419057cde156..031b2adf198475d3ac7ab5448e6cfbdc9b85f7d3 100644
--- a/std/event/lock.zig
+++ b/std/event/lock.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/event/locked.zig b/std/event/locked.zig
index 6718b1bf9cea8d2f8055c93312abbd48440e5d18..1ceaa33530be149ed6d80a37149e9d2b9a6aa63a 100644
--- a/std/event/locked.zig
+++ b/std/event/locked.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const Lock = std.event.Lock;
const Loop = std.event.Loop;
diff --git a/std/event/loop.zig b/std/event/loop.zig
index 55a1538f0cb82afdeb9178cadbc58fdbead3dc24..a327d0379288711ae6db92d07ae0907944d841c0 100644
--- a/std/event/loop.zig
+++ b/std/event/loop.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/event/net.zig b/std/event/net.zig
index 48461c3d815ccef39bbe8118fe53b5b96ba9cbf3..687c1199205c4ac85146e5480087594f2cde6206 100644
--- a/std/event/net.zig
+++ b/std/event/net.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const testing = std.testing;
const event = std.event;
diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig
index 26ccd12b73362bb3a6b0a0fe4d44e56b89e3a1bb..25b0f0e74b6bf515be88e2db6fe52a013e028d0d 100644
--- a/std/event/rwlock.zig
+++ b/std/event/rwlock.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/event/rwlocked.zig b/std/event/rwlocked.zig
index d305b1791eb32cd8ac3cc90c980b79baa100ad29..0448e0298e791f4ea8768feea0d39446ec48f60c 100644
--- a/std/event/rwlocked.zig
+++ b/std/event/rwlocked.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const RwLock = std.event.RwLock;
const Loop = std.event.Loop;
diff --git a/std/fmt.zig b/std/fmt.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e01ba2033b6af33749699262d29d1432c0bb2eff
--- /dev/null
+++ b/std/fmt.zig
@@ -0,0 +1,1441 @@
+const std = @import("std.zig");
+const math = std.math;
+const debug = std.debug;
+const assert = debug.assert;
+const testing = std.testing;
+const mem = std.mem;
+const builtin = @import("builtin");
+const errol = @import("fmt/errol.zig");
+const lossyCast = std.math.lossyCast;
+
+const max_int_digits = 65;
+
+/// Renders fmt string with args, calling output with slices of bytes.
+/// If `output` returns an error, the error is returned from `format` and
+/// `output` is not called again.
+pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
+ const State = enum {
+ Start,
+ OpenBrace,
+ CloseBrace,
+ FormatString,
+ Pointer,
+ };
+
+ comptime var start_index = 0;
+ comptime var state = State.Start;
+ comptime var next_arg = 0;
+
+ inline for (fmt) |c, i| {
+ switch (state) {
+ State.Start => switch (c) {
+ '{' => {
+ if (start_index < i) {
+ try output(context, fmt[start_index..i]);
+ }
+ start_index = i;
+ state = State.OpenBrace;
+ },
+
+ '}' => {
+ if (start_index < i) {
+ try output(context, fmt[start_index..i]);
+ }
+ state = State.CloseBrace;
+ },
+ else => {},
+ },
+ State.OpenBrace => switch (c) {
+ '{' => {
+ state = State.Start;
+ start_index = i;
+ },
+ '}' => {
+ try formatType(args[next_arg], fmt[0..0], context, Errors, output);
+ next_arg += 1;
+ state = State.Start;
+ start_index = i + 1;
+ },
+ '*' => state = State.Pointer,
+ else => {
+ state = State.FormatString;
+ },
+ },
+ State.CloseBrace => switch (c) {
+ '}' => {
+ state = State.Start;
+ start_index = i;
+ },
+ else => @compileError("Single '}' encountered in format string"),
+ },
+ State.FormatString => switch (c) {
+ '}' => {
+ const s = start_index + 1;
+ try formatType(args[next_arg], fmt[s..i], context, Errors, output);
+ next_arg += 1;
+ state = State.Start;
+ start_index = i + 1;
+ },
+ else => {},
+ },
+ State.Pointer => switch (c) {
+ '}' => {
+ try output(context, @typeName(@typeOf(args[next_arg]).Child));
+ try output(context, "@");
+ try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
+ next_arg += 1;
+ state = State.Start;
+ start_index = i + 1;
+ },
+ else => @compileError("Unexpected format character after '*'"),
+ },
+ }
+ }
+ comptime {
+ if (args.len != next_arg) {
+ @compileError("Unused arguments");
+ }
+ if (state != State.Start) {
+ @compileError("Incomplete format string: " ++ fmt);
+ }
+ }
+ if (start_index < fmt.len) {
+ try output(context, fmt[start_index..]);
+ }
+}
+
+pub fn formatType(
+ value: var,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ const T = @typeOf(value);
+ if (T == anyerror) {
+ try output(context, "error.");
+ return output(context, @errorName(value));
+ }
+ switch (@typeInfo(T)) {
+ builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
+ return formatValue(value, fmt, context, Errors, output);
+ },
+ builtin.TypeId.Void => {
+ return output(context, "void");
+ },
+ builtin.TypeId.Bool => {
+ return output(context, if (value) "true" else "false");
+ },
+ builtin.TypeId.Optional => {
+ if (value) |payload| {
+ return formatType(payload, fmt, context, Errors, output);
+ } else {
+ return output(context, "null");
+ }
+ },
+ builtin.TypeId.ErrorUnion => {
+ if (value) |payload| {
+ return formatType(payload, fmt, context, Errors, output);
+ } else |err| {
+ return formatType(err, fmt, context, Errors, output);
+ }
+ },
+ builtin.TypeId.ErrorSet => {
+ try output(context, "error.");
+ return output(context, @errorName(value));
+ },
+ builtin.TypeId.Promise => {
+ return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
+ },
+ builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
+ const has_cust_fmt = comptime cf: {
+ const info = @typeInfo(T);
+ const defs = switch (info) {
+ builtin.TypeId.Struct => |s| s.defs,
+ builtin.TypeId.Union => |u| u.defs,
+ builtin.TypeId.Enum => |e| e.defs,
+ else => unreachable,
+ };
+
+ for (defs) |def| {
+ if (mem.eql(u8, def.name, "format")) {
+ break :cf true;
+ }
+ }
+ break :cf false;
+ };
+ if (has_cust_fmt) return value.format(fmt, context, Errors, output);
+
+ try output(context, @typeName(T));
+ switch (comptime @typeId(T)) {
+ builtin.TypeId.Enum => {
+ try output(context, ".");
+ try formatType(@tagName(value), "", context, Errors, output);
+ return;
+ },
+ builtin.TypeId.Struct => {
+ comptime var field_i = 0;
+ inline while (field_i < @memberCount(T)) : (field_i += 1) {
+ if (field_i == 0) {
+ try output(context, "{ .");
+ } else {
+ try output(context, ", .");
+ }
+ try output(context, @memberName(T, field_i));
+ try output(context, " = ");
+ try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);
+ }
+ try output(context, " }");
+ },
+ builtin.TypeId.Union => {
+ const info = @typeInfo(T).Union;
+ if (info.tag_type) |UnionTagType| {
+ try output(context, "{ .");
+ try output(context, @tagName(UnionTagType(value)));
+ try output(context, " = ");
+ inline for (info.fields) |u_field| {
+ if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
+ try formatType(@field(value, u_field.name), "", context, Errors, output);
+ }
+ }
+ try output(context, " }");
+ } else {
+ try format(context, Errors, output, "@{x}", @ptrToInt(&value));
+ }
+ },
+ else => unreachable,
+ }
+ return;
+ },
+ builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
+ builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
+ builtin.TypeId.Array => |info| {
+ if (info.child == u8) {
+ return formatText(value, fmt, context, Errors, output);
+ }
+ return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
+ },
+ builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
+ return formatType(value.*, fmt, context, Errors, output);
+ },
+ else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
+ },
+ builtin.TypeInfo.Pointer.Size.Many => {
+ if (ptr_info.child == u8) {
+ if (fmt.len > 0 and fmt[0] == 's') {
+ const len = std.cstr.len(value);
+ return formatText(value[0..len], fmt, context, Errors, output);
+ }
+ }
+ return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
+ },
+ builtin.TypeInfo.Pointer.Size.Slice => {
+ if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
+ return formatText(value, fmt, context, Errors, output);
+ }
+ const casted_value = ([]const u8)(value);
+ return output(context, casted_value);
+ },
+ builtin.TypeInfo.Pointer.Size.C => {
+ return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
+ },
+ },
+ builtin.TypeId.Array => |info| {
+ if (info.child == u8) {
+ return formatText(value, fmt, context, Errors, output);
+ }
+ return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
+ },
+ builtin.TypeId.Fn => {
+ return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
+ },
+ else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
+ }
+}
+
+fn formatValue(
+ value: var,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (fmt.len > 0) {
+ if (fmt[0] == 'B') {
+ comptime var width: ?usize = null;
+ if (fmt.len > 1) {
+ if (fmt[1] == 'i') {
+ if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
+ return formatBytes(value, width, 1024, context, Errors, output);
+ }
+ width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
+ }
+ return formatBytes(value, width, 1000, context, Errors, output);
+ }
+ }
+
+ const T = @typeOf(value);
+ switch (@typeId(T)) {
+ builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
+ builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
+ builtin.TypeId.ComptimeInt => {
+ const Int = math.IntFittingRange(value, value);
+ return formatIntValue(Int(value), fmt, context, Errors, output);
+ },
+ else => comptime unreachable,
+ }
+}
+
+pub fn formatIntValue(
+ value: var,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ comptime var radix = 10;
+ comptime var uppercase = false;
+ comptime var width = 0;
+ if (fmt.len > 0) {
+ switch (fmt[0]) {
+ 'c' => {
+ if (@typeOf(value).bit_count <= 8) {
+ if (fmt.len > 1)
+ @compileError("Unknown format character: " ++ []u8{fmt[1]});
+ return formatAsciiChar(u8(value), context, Errors, output);
+ }
+ },
+ 'b' => {
+ radix = 2;
+ uppercase = false;
+ width = 0;
+ },
+ 'd' => {
+ radix = 10;
+ uppercase = false;
+ width = 0;
+ },
+ 'x' => {
+ radix = 16;
+ uppercase = false;
+ width = 0;
+ },
+ 'X' => {
+ radix = 16;
+ uppercase = true;
+ width = 0;
+ },
+ else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
+ }
+ if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
+ }
+ return formatInt(value, radix, uppercase, width, context, Errors, output);
+}
+
+fn formatFloatValue(
+ value: var,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ comptime var width: ?usize = null;
+ comptime var float_fmt = 'e';
+ if (fmt.len > 0) {
+ float_fmt = fmt[0];
+ if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
+ }
+
+ switch (float_fmt) {
+ 'e' => try formatFloatScientific(value, width, context, Errors, output),
+ '.' => try formatFloatDecimal(value, width, context, Errors, output),
+ else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
+ }
+}
+
+pub fn formatText(
+ bytes: []const u8,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (fmt.len > 0) {
+ if (fmt[0] == 's') {
+ comptime var width = 0;
+ if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
+ return formatBuf(bytes, width, context, Errors, output);
+ } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
+ for (bytes) |c| {
+ try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
+ }
+ return;
+ } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
+ }
+ return output(context, bytes);
+}
+
+pub fn formatAsciiChar(
+ c: u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ return output(context, (*[1]u8)(&c)[0..]);
+}
+
+pub fn formatBuf(
+ buf: []const u8,
+ width: usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ try output(context, buf);
+
+ var leftover_padding = if (width > buf.len) (width - buf.len) else return;
+ const pad_byte: u8 = ' ';
+ while (leftover_padding > 0) : (leftover_padding -= 1) {
+ try output(context, (*[1]u8)(&pad_byte)[0..1]);
+ }
+}
+
+// Print a float in scientific notation to the specified precision. Null uses full precision.
+// It should be the case that every full precision, printed value can be re-parsed back to the
+// same type unambiguously.
+pub fn formatFloatScientific(
+ value: var,
+ maybe_precision: ?usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ var x = @floatCast(f64, value);
+
+ // Errol doesn't handle these special cases.
+ if (math.signbit(x)) {
+ try output(context, "-");
+ x = -x;
+ }
+
+ if (math.isNan(x)) {
+ return output(context, "nan");
+ }
+ if (math.isPositiveInf(x)) {
+ return output(context, "inf");
+ }
+ if (x == 0.0) {
+ try output(context, "0");
+
+ if (maybe_precision) |precision| {
+ if (precision != 0) {
+ try output(context, ".");
+ var i: usize = 0;
+ while (i < precision) : (i += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ try output(context, ".0");
+ }
+
+ try output(context, "e+00");
+ return;
+ }
+
+ var buffer: [32]u8 = undefined;
+ var float_decimal = errol.errol3(x, buffer[0..]);
+
+ if (maybe_precision) |precision| {
+ errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
+
+ try output(context, float_decimal.digits[0..1]);
+
+ // {e0} case prints no `.`
+ if (precision != 0) {
+ try output(context, ".");
+
+ var printed: usize = 0;
+ if (float_decimal.digits.len > 1) {
+ const num_digits = math.min(float_decimal.digits.len, precision + 1);
+ try output(context, float_decimal.digits[1..num_digits]);
+ printed += num_digits - 1;
+ }
+
+ while (printed < precision) : (printed += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ try output(context, float_decimal.digits[0..1]);
+ try output(context, ".");
+ if (float_decimal.digits.len > 1) {
+ const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
+
+ try output(context, float_decimal.digits[1..num_digits]);
+ } else {
+ try output(context, "0");
+ }
+ }
+
+ try output(context, "e");
+ const exp = float_decimal.exp - 1;
+
+ if (exp >= 0) {
+ try output(context, "+");
+ if (exp > -10 and exp < 10) {
+ try output(context, "0");
+ }
+ try formatInt(exp, 10, false, 0, context, Errors, output);
+ } else {
+ try output(context, "-");
+ if (exp > -10 and exp < 10) {
+ try output(context, "0");
+ }
+ try formatInt(-exp, 10, false, 0, context, Errors, output);
+ }
+}
+
+// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
+// By default floats are printed at full precision (no rounding).
+pub fn formatFloatDecimal(
+ value: var,
+ maybe_precision: ?usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ var x = f64(value);
+
+ // Errol doesn't handle these special cases.
+ if (math.signbit(x)) {
+ try output(context, "-");
+ x = -x;
+ }
+
+ if (math.isNan(x)) {
+ return output(context, "nan");
+ }
+ if (math.isPositiveInf(x)) {
+ return output(context, "inf");
+ }
+ if (x == 0.0) {
+ try output(context, "0");
+
+ if (maybe_precision) |precision| {
+ if (precision != 0) {
+ try output(context, ".");
+ var i: usize = 0;
+ while (i < precision) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, ".0");
+ }
+ } else {
+ try output(context, "0");
+ }
+
+ return;
+ }
+
+ // non-special case, use errol3
+ var buffer: [32]u8 = undefined;
+ var float_decimal = errol.errol3(x, buffer[0..]);
+
+ if (maybe_precision) |precision| {
+ errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
+
+ // exp < 0 means the leading is always 0 as errol result is normalized.
+ var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
+
+ // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
+ var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
+
+ if (num_digits_whole > 0) {
+ // We may have to zero pad, for instance 1e4 requires zero padding.
+ try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+
+ var i = num_digits_whole_no_pad;
+ while (i < num_digits_whole) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, "0");
+ }
+
+ // {.0} special case doesn't want a trailing '.'
+ if (precision == 0) {
+ return;
+ }
+
+ try output(context, ".");
+
+ // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
+ var printed: usize = 0;
+
+ // Zero-fill until we reach significant digits or run out of precision.
+ if (float_decimal.exp <= 0) {
+ const zero_digit_count = @intCast(usize, -float_decimal.exp);
+ const zeros_to_print = math.min(zero_digit_count, precision);
+
+ var i: usize = 0;
+ while (i < zeros_to_print) : (i += 1) {
+ try output(context, "0");
+ printed += 1;
+ }
+
+ if (printed >= precision) {
+ return;
+ }
+ }
+
+ // Remaining fractional portion, zero-padding if insufficient.
+ assert(precision >= printed);
+ if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
+ try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
+ return;
+ } else {
+ try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ printed += float_decimal.digits.len - num_digits_whole_no_pad;
+
+ while (printed < precision) : (printed += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ // exp < 0 means the leading is always 0 as errol result is normalized.
+ var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
+
+ // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
+ var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
+
+ if (num_digits_whole > 0) {
+ // We may have to zero pad, for instance 1e4 requires zero padding.
+ try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+
+ var i = num_digits_whole_no_pad;
+ while (i < num_digits_whole) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, "0");
+ }
+
+ // Omit `.` if no fractional portion
+ if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
+ return;
+ }
+
+ try output(context, ".");
+
+ // Zero-fill until we reach significant digits or run out of precision.
+ if (float_decimal.exp < 0) {
+ const zero_digit_count = @intCast(usize, -float_decimal.exp);
+
+ var i: usize = 0;
+ while (i < zero_digit_count) : (i += 1) {
+ try output(context, "0");
+ }
+ }
+
+ try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ }
+}
+
+pub fn formatBytes(
+ value: var,
+ width: ?usize,
+ comptime radix: usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (value == 0) {
+ return output(context, "0B");
+ }
+
+ const mags_si = " kMGTPEZY";
+ const mags_iec = " KMGTPEZY";
+ const magnitude = switch (radix) {
+ 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
+ 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
+ else => unreachable,
+ };
+ const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
+ const suffix = switch (radix) {
+ 1000 => mags_si[magnitude],
+ 1024 => mags_iec[magnitude],
+ else => unreachable,
+ };
+
+ try formatFloatDecimal(new_value, width, context, Errors, output);
+
+ if (suffix == ' ') {
+ return output(context, "B");
+ }
+
+ const buf = switch (radix) {
+ 1000 => []u8{ suffix, 'B' },
+ 1024 => []u8{ suffix, 'i', 'B' },
+ else => unreachable,
+ };
+ return output(context, buf);
+}
+
+pub fn formatInt(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ width: usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (@typeOf(value).is_signed) {
+ return formatIntSigned(value, base, uppercase, width, context, Errors, output);
+ } else {
+ return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
+ }
+}
+
+fn formatIntSigned(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ width: usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ const uint = @IntType(false, @typeOf(value).bit_count);
+ if (value < 0) {
+ const minus_sign: u8 = '-';
+ try output(context, (*[1]u8)(&minus_sign)[0..]);
+ const new_value = @intCast(uint, -(value + 1)) + 1;
+ const new_width = if (width == 0) 0 else (width - 1);
+ return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
+ } else if (width == 0) {
+ return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
+ } else {
+ const plus_sign: u8 = '+';
+ try output(context, (*[1]u8)(&plus_sign)[0..]);
+ const new_value = @intCast(uint, value);
+ const new_width = if (width == 0) 0 else (width - 1);
+ return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
+ }
+}
+
+fn formatIntUnsigned(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ width: usize,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+) Errors!void {
+ // max_int_digits accounts for the minus sign. when printing an unsigned
+ // number we don't need to do that.
+ var buf: [max_int_digits - 1]u8 = undefined;
+ const min_int_bits = comptime math.max(@typeOf(value).bit_count, @typeOf(base).bit_count);
+ const MinInt = @IntType(@typeOf(value).is_signed, min_int_bits);
+ var a: MinInt = value;
+ var index: usize = buf.len;
+
+ while (true) {
+ const digit = a % base;
+ index -= 1;
+ buf[index] = digitToChar(@intCast(u8, digit), uppercase);
+ a /= base;
+ if (a == 0) break;
+ }
+
+ const digits_buf = buf[index..];
+ const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
+
+ if (padding > index) {
+ const zero_byte: u8 = '0';
+ var leftover_padding = padding - index;
+ while (true) {
+ try output(context, (*[1]u8)(&zero_byte)[0..]);
+ leftover_padding -= 1;
+ if (leftover_padding == 0) break;
+ }
+ mem.set(u8, buf[0..index], '0');
+ return output(context, buf);
+ } else {
+ const padded_buf = buf[index - padding ..];
+ mem.set(u8, padded_buf[0..padding], '0');
+ return output(context, padded_buf);
+ }
+}
+
+pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
+ var context = FormatIntBuf{
+ .out_buf = out_buf,
+ .index = 0,
+ };
+ formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
+ return context.index;
+}
+const FormatIntBuf = struct {
+ out_buf: []u8,
+ index: usize,
+};
+fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
+ mem.copy(u8, context.out_buf[context.index..], bytes);
+ context.index += bytes.len;
+}
+
+pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
+ if (!T.is_signed) return parseUnsigned(T, buf, radix);
+ if (buf.len == 0) return T(0);
+ if (buf[0] == '-') {
+ return math.negate(try parseUnsigned(T, buf[1..], radix));
+ } else if (buf[0] == '+') {
+ return parseUnsigned(T, buf[1..], radix);
+ } else {
+ return parseUnsigned(T, buf, radix);
+ }
+}
+
+test "fmt.parseInt" {
+ testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
+ testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
+ testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
+ testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
+ testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
+}
+
+const ParseUnsignedError = error{
+ /// The result cannot fit in the type specified
+ Overflow,
+
+ /// The input had a byte that was not a digit
+ InvalidCharacter,
+};
+
+pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
+ var x: T = 0;
+
+ for (buf) |c| {
+ const digit = try charToDigit(c, radix);
+
+ if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
+ x = try math.add(T, x, try math.cast(T, digit));
+ }
+
+ return x;
+}
+
+test "fmt.parseUnsigned" {
+ testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
+ testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
+ testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
+
+ testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
+ testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
+
+ testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
+
+ testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
+ testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
+
+ testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
+ testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
+
+ testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
+
+ // these numbers should fit even though the radix itself doesn't fit in the destination type
+ testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
+ testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
+ testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
+ testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
+ testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
+ testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
+}
+
+pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
+
+test "fmt.parseFloat" {
+ _ = @import("fmt/parse_float.zig");
+}
+
+pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
+ const value = switch (c) {
+ '0'...'9' => c - '0',
+ 'A'...'Z' => c - 'A' + 10,
+ 'a'...'z' => c - 'a' + 10,
+ else => return error.InvalidCharacter,
+ };
+
+ if (value >= radix) return error.InvalidCharacter;
+
+ return value;
+}
+
+fn digitToChar(digit: u8, uppercase: bool) u8 {
+ return switch (digit) {
+ 0...9 => digit + '0',
+ 10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
+ else => unreachable,
+ };
+}
+
+const BufPrintContext = struct {
+ remaining: []u8,
+};
+
+fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
+ if (context.remaining.len < bytes.len) return error.BufferTooSmall;
+ mem.copy(u8, context.remaining, bytes);
+ context.remaining = context.remaining[bytes.len..];
+}
+
+pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
+ var context = BufPrintContext{ .remaining = buf };
+ try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
+ return buf[0 .. buf.len - context.remaining.len];
+}
+
+pub const AllocPrintError = error{OutOfMemory};
+
+pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
+ var size: usize = 0;
+ format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
+ const buf = try allocator.alloc(u8, size);
+ return bufPrint(buf, fmt, args) catch |err| switch (err) {
+ error.BufferTooSmall => unreachable, // we just counted the size above
+ };
+}
+
+fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
+ size.* += bytes.len;
+}
+
+test "buf print int" {
+ var buffer: [max_int_digits]u8 = undefined;
+ const buf = buffer[0..];
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
+
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
+
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
+
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
+ testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
+}
+
+fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
+ return buf[0..formatIntBuf(buf, value, base, uppercase, width)];
+}
+
+test "parse u64 digit too big" {
+ _ = parseUnsigned(u64, "123a", 10) catch |err| {
+ if (err == error.InvalidCharacter) return;
+ unreachable;
+ };
+ unreachable;
+}
+
+test "parse unsigned comptime" {
+ comptime {
+ testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
+ }
+}
+
+test "fmt.format" {
+ {
+ const value: ?i32 = 1234;
+ try testFmt("optional: 1234\n", "optional: {}\n", value);
+ }
+ {
+ const value: ?i32 = null;
+ try testFmt("optional: null\n", "optional: {}\n", value);
+ }
+ {
+ const value: anyerror!i32 = 1234;
+ try testFmt("error union: 1234\n", "error union: {}\n", value);
+ }
+ {
+ const value: anyerror!i32 = error.InvalidChar;
+ try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
+ }
+ {
+ const value: u3 = 0b101;
+ try testFmt("u3: 5\n", "u3: {}\n", value);
+ }
+ {
+ const value: u8 = 'a';
+ try testFmt("u8: a\n", "u8: {c}\n", value);
+ }
+ {
+ const value: u8 = 0b1100;
+ try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ var context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
+ var res = buf1[0 .. buf1.len - context.remaining.len];
+ testing.expect(mem.eql(u8, res, "1234"));
+
+ context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
+ res = buf1[0 .. buf1.len - context.remaining.len];
+ testing.expect(mem.eql(u8, res, "a"));
+
+ context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
+ res = buf1[0 .. buf1.len - context.remaining.len];
+ testing.expect(mem.eql(u8, res, "1100"));
+ }
+ {
+ const value: [3]u8 = "abc";
+ try testFmt("array: abc\n", "array: {}\n", value);
+ try testFmt("array: abc\n", "array: {}\n", &value);
+
+ var buf: [100]u8 = undefined;
+ try testFmt(
+ try bufPrint(buf[0..], "array: [3]u8@{x}\n", @ptrToInt(&value)),
+ "array: {*}\n",
+ &value,
+ );
+ }
+ {
+ const value: []const u8 = "abc";
+ try testFmt("slice: abc\n", "slice: {}\n", value);
+ }
+ {
+ const value = @intToPtr(*i32, 0xdeadbeef);
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
+ }
+ try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
+ try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
+ try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
+ try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
+ try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
+ try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
+ {
+ const Struct = struct {
+ field: u8,
+ };
+ const value = Struct{ .field = 42 };
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", value);
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", &value);
+ }
+ {
+ const Struct = struct {
+ a: u0,
+ b: u1,
+ };
+ const value = Struct{ .a = 0, .b = 1 };
+ try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
+ }
+ {
+ const Enum = enum {
+ One,
+ Two,
+ };
+ const value = Enum.Two;
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = 1.34;
+ const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
+ testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = 12.34;
+ const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
+ testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = -12.34e10;
+ const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
+ }
+ {
+ // This fails on release due to a minor rounding difference.
+ // --release-fast outputs 9.999960000000001e-40 vs. the expected.
+ // TODO fix this, it should be the same in Debug and ReleaseFast
+ if (builtin.mode == builtin.Mode.Debug) {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 9.999960e-40;
+ const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
+ }
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 1.409706e-42;
+ const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = @bitCast(f32, u32(814313563));
+ const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = @bitCast(f32, u32(1006632960));
+ const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
+ }
+ {
+ // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
+ // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
+ var buf1: [32]u8 = undefined;
+ const value: f64 = @bitCast(f32, u32(1203982400));
+ const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
+ testing.expect(mem.eql(u8, result, "f64: nan\n"));
+ }
+ if (builtin.arch != builtin.Arch.arm) {
+ // negative nan is not defined by IEE 754,
+ // and ARM thus normalizes it to positive nan
+ var buf1: [32]u8 = undefined;
+ const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
+ testing.expect(mem.eql(u8, result, "f64: -nan\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
+ testing.expect(mem.eql(u8, result, "f64: inf\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
+ testing.expect(mem.eql(u8, result, "f64: -inf\n"));
+ }
+ {
+ var buf1: [64]u8 = undefined;
+ const value: f64 = 1.52314e+29;
+ const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = 1.1234;
+ const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
+ testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = 1234.567;
+ const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
+ testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = -11.1234;
+ const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
+ // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
+ // -11.12339... is rounded back up to -11.1234
+ testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f32 = 91.12345;
+ const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 91.12345678901235;
+ const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 0.0;
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 5.700;
+ const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 6\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 9.999;
+ const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 1.0;
+ const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 0.0003;
+ const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 1.40130e-45;
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = 9.999960e-40;
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
+ }
+ // libc checks
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(916964781)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(925353389)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(1036831278)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(1065353133)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
+ }
+ {
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(1092616192)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
+ }
+ // libc differences
+ {
+ var buf1: [32]u8 = undefined;
+ // This is 0.015625 exactly according to gdb. We thus round down,
+ // however glibc rounds up for some reason. This occurs for all
+ // floats of the form x.yyyy25 on a precision point.
+ const value: f64 = f64(@bitCast(f32, u32(1015021568)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
+ }
+ // std-windows-x86_64-Debug-bare test case fails
+ {
+ // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
+ // also rounds to 630 so I'm inclined to believe libc is not
+ // optimal here.
+ var buf1: [32]u8 = undefined;
+ const value: f64 = f64(@bitCast(f32, u32(1518338049)));
+ const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
+ testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
+ }
+ //custom type format
+ {
+ const Vec2 = struct {
+ const SelfType = @This();
+ x: f32,
+ y: f32,
+
+ pub fn format(
+ self: SelfType,
+ comptime fmt: []const u8,
+ context: var,
+ comptime Errors: type,
+ output: fn (@typeOf(context), []const u8) Errors!void,
+ ) Errors!void {
+ switch (fmt.len) {
+ 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
+ 1 => switch (fmt[0]) {
+ //point format
+ 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
+ //dimension format
+ 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
+ else => unreachable,
+ },
+ else => unreachable,
+ }
+ }
+ };
+
+ var buf1: [32]u8 = undefined;
+ var value = Vec2{
+ .x = 10.2,
+ .y = 2.22,
+ };
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
+
+ // same thing but not passing a pointer
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
+ }
+ //struct format
+ {
+ const S = struct {
+ a: u32,
+ b: anyerror,
+ };
+
+ const inst = S{
+ .a = 456,
+ .b = error.Unused,
+ };
+
+ try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
+ }
+ //union format
+ {
+ const TU = union(enum) {
+ float: f32,
+ int: u32,
+ };
+
+ const UU = union {
+ float: f32,
+ int: u32,
+ };
+
+ const EU = extern union {
+ float: f32,
+ int: u32,
+ };
+
+ const tu_inst = TU{ .int = 123 };
+ const uu_inst = UU{ .int = 456 };
+ const eu_inst = EU{ .float = 321.123 };
+
+ try testFmt("TU{ .int = 123 }", "{}", tu_inst);
+
+ var buf: [100]u8 = undefined;
+ const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
+ testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+
+ const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
+ testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
+ }
+ //enum format
+ {
+ const E = enum {
+ One,
+ Two,
+ Three,
+ };
+
+ const inst = E.Two;
+
+ try testFmt("E.Two", "{}", inst);
+ }
+ //print bytes as hex
+ {
+ const some_bytes = "\xCA\xFE\xBA\xBE";
+ try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
+ try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
+ //Test Slices
+ try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
+ try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
+ const bytes_with_zeros = "\x00\x0E\xBA\xBE";
+ try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
+ }
+}
+
+fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
+ var buf: [100]u8 = undefined;
+ const result = try bufPrint(buf[0..], template, args);
+ if (mem.eql(u8, result, expected)) return;
+
+ std.debug.warn("\n====== expected this output: =========\n");
+ std.debug.warn("{}", expected);
+ std.debug.warn("\n======== instead found this: =========\n");
+ std.debug.warn("{}", result);
+ std.debug.warn("\n======================================\n");
+ return error.TestFailed;
+}
+
+pub fn trim(buf: []const u8) []const u8 {
+ var start: usize = 0;
+ while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
+
+ var end: usize = buf.len;
+ while (true) {
+ if (end > start) {
+ const new_end = end - 1;
+ if (isWhiteSpace(buf[new_end])) {
+ end = new_end;
+ continue;
+ }
+ }
+ break;
+ }
+ return buf[start..end];
+}
+
+test "fmt.trim" {
+ testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
+ testing.expect(mem.eql(u8, "", trim(" ")));
+ testing.expect(mem.eql(u8, "", trim("")));
+ testing.expect(mem.eql(u8, "abc", trim(" abc")));
+ testing.expect(mem.eql(u8, "abc", trim("abc ")));
+}
+
+pub fn isWhiteSpace(byte: u8) bool {
+ return switch (byte) {
+ ' ', '\t', '\n', '\r' => true,
+ else => false,
+ };
+}
+
+pub fn hexToBytes(out: []u8, input: []const u8) !void {
+ if (out.len * 2 < input.len)
+ return error.InvalidLength;
+
+ var in_i: usize = 0;
+ while (in_i != input.len) : (in_i += 2) {
+ const hi = try charToDigit(input[in_i], 16);
+ const lo = try charToDigit(input[in_i + 1], 16);
+ out[in_i / 2] = (hi << 4) | lo;
+ }
+}
+
+test "fmt.hexToBytes" {
+ const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
+ var pb: [32]u8 = undefined;
+ try hexToBytes(pb[0..], test_hex_str);
+ try testFmt(test_hex_str, "{X}", pb);
+}
diff --git a/std/fmt/errol.zig b/std/fmt/errol.zig
new file mode 100644
index 0000000000000000000000000000000000000000..9304c548743a67da431b4be55c0f7cb95bbb94ca
--- /dev/null
+++ b/std/fmt/errol.zig
@@ -0,0 +1,704 @@
+const std = @import("../std.zig");
+const enum3 = @import("errol/enum3.zig").enum3;
+const enum3_data = @import("errol/enum3.zig").enum3_data;
+const lookup_table = @import("errol/lookup.zig").lookup_table;
+const HP = @import("errol/lookup.zig").HP;
+const math = std.math;
+const mem = std.mem;
+const assert = std.debug.assert;
+
+pub const FloatDecimal = struct {
+ digits: []u8,
+ exp: i32,
+};
+
+pub const RoundMode = enum {
+ // Round only the fractional portion (e.g. 1234.23 has precision 2)
+ Decimal,
+ // Round the entire whole/fractional portion (e.g. 1.23423e3 has precision 5)
+ Scientific,
+};
+
+/// Round a FloatDecimal as returned by errol3 to the specified fractional precision.
+/// All digits after the specified precision should be considered invalid.
+pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: RoundMode) void {
+ // The round digit refers to the index which we should look at to determine
+ // whether we need to round to match the specified precision.
+ var round_digit: usize = 0;
+
+ switch (mode) {
+ RoundMode.Decimal => {
+ if (float_decimal.exp >= 0) {
+ round_digit = precision + @intCast(usize, float_decimal.exp);
+ } else {
+ // if a small negative exp, then adjust we need to offset by the number
+ // of leading zeros that will occur.
+ const min_exp_required = @intCast(usize, -float_decimal.exp);
+ if (precision > min_exp_required) {
+ round_digit = precision - min_exp_required;
+ }
+ }
+ },
+ RoundMode.Scientific => {
+ round_digit = 1 + precision;
+ },
+ }
+
+ // It suffices to look at just this digit. We don't round and propagate say 0.04999 to 0.05
+ // first, and then to 0.1 in the case of a {.1} single precision.
+
+ // Find the digit which will signify the round point and start rounding backwards.
+ if (round_digit < float_decimal.digits.len and float_decimal.digits[round_digit] - '0' >= 5) {
+ assert(round_digit >= 0);
+
+ var i = round_digit;
+ while (true) {
+ if (i == 0) {
+ // Rounded all the way past the start. This was of the form 9.999...
+ // Slot the new digit in place and increase the exponent.
+ float_decimal.exp += 1;
+
+ // Re-size the buffer to use the reserved leading byte.
+ const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
+ float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
+ float_decimal.digits[0] = '1';
+ return;
+ }
+
+ i -= 1;
+
+ const new_value = (float_decimal.digits[i] - '0' + 1) % 10;
+ float_decimal.digits[i] = new_value + '0';
+
+ // must continue rounding until non-9
+ if (new_value != 0) {
+ return;
+ }
+ }
+ }
+}
+
+/// Corrected Errol3 double to ASCII conversion.
+pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
+ const bits = @bitCast(u64, value);
+ const i = tableLowerBound(bits);
+ if (i < enum3.len and enum3[i] == bits) {
+ const data = enum3_data[i];
+ const digits = buffer[1 .. data.str.len + 1];
+ mem.copy(u8, digits, data.str);
+ return FloatDecimal{
+ .digits = digits,
+ .exp = data.exp,
+ };
+ }
+
+ return errol3u(value, buffer);
+}
+
+/// Uncorrected Errol3 double to ASCII conversion.
+fn errol3u(val: f64, buffer: []u8) FloatDecimal {
+ // check if in integer or fixed range
+ if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
+ return errolInt(val, buffer);
+ } else if (val >= 16.0 and val < 9.007199254740992e15) {
+ return errolFixed(val, buffer);
+ }
+
+ // normalize the midpoint
+
+ const e = math.frexp(val).exponent;
+ var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
+ if (exp < 20) {
+ exp = 20;
+ } else if (@intCast(usize, exp) >= lookup_table.len) {
+ exp = @intCast(i16, lookup_table.len - 1);
+ }
+
+ var mid = lookup_table[@intCast(usize, exp)];
+ mid = hpProd(mid, val);
+ const lten = lookup_table[@intCast(usize, exp)].val;
+
+ exp -= 307;
+
+ var ten: f64 = 1.0;
+
+ while (mid.val > 10.0 or (mid.val == 10.0 and mid.off >= 0.0)) {
+ exp += 1;
+ hpDiv10(&mid);
+ ten /= 10.0;
+ }
+
+ while (mid.val < 1.0 or (mid.val == 1.0 and mid.off < 0.0)) {
+ exp -= 1;
+ hpMul10(&mid);
+ ten *= 10.0;
+ }
+
+ // compute boundaries
+ var high = HP{
+ .val = mid.val,
+ .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
+ };
+ var low = HP{
+ .val = mid.val,
+ .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
+ };
+
+ hpNormalize(&high);
+ hpNormalize(&low);
+
+ // normalized boundaries
+
+ while (high.val > 10.0 or (high.val == 10.0 and high.off >= 0.0)) {
+ exp += 1;
+ hpDiv10(&high);
+ hpDiv10(&low);
+ }
+
+ while (high.val < 1.0 or (high.val == 1.0 and high.off < 0.0)) {
+ exp -= 1;
+ hpMul10(&high);
+ hpMul10(&low);
+ }
+
+ // digit generation
+
+ // We generate digits starting at index 1. If rounding a buffer later then it may be
+ // required to generate a preceding digit in some cases (9.999) in which case we use
+ // the 0-index for this extra digit.
+ var buf_index: usize = 1;
+ while (true) {
+ var hdig = @floatToInt(u8, math.floor(high.val));
+ if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
+
+ var ldig = @floatToInt(u8, math.floor(low.val));
+ if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
+
+ if (ldig != hdig) break;
+
+ buffer[buf_index] = hdig + '0';
+ buf_index += 1;
+ high.val -= @intToFloat(f64, hdig);
+ low.val -= @intToFloat(f64, ldig);
+ hpMul10(&high);
+ hpMul10(&low);
+ }
+
+ const tmp = (high.val + low.val) / 2.0;
+ var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
+ if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
+
+ buffer[buf_index] = mdig + '0';
+ buf_index += 1;
+
+ return FloatDecimal{
+ .digits = buffer[1..buf_index],
+ .exp = exp,
+ };
+}
+
+fn tableLowerBound(k: u64) usize {
+ var i = enum3.len;
+ var j: usize = 0;
+
+ while (j < enum3.len) {
+ if (enum3[j] < k) {
+ j = 2 * j + 2;
+ } else {
+ i = j;
+ j = 2 * j + 1;
+ }
+ }
+
+ return i;
+}
+
+/// Compute the product of an HP number and a double.
+/// @in: The HP number.
+/// @val: The double.
+/// &returns: The HP number.
+fn hpProd(in: HP, val: f64) HP {
+ var hi: f64 = undefined;
+ var lo: f64 = undefined;
+ split(in.val, &hi, &lo);
+
+ var hi2: f64 = undefined;
+ var lo2: f64 = undefined;
+ split(val, &hi2, &lo2);
+
+ const p = in.val * val;
+ const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
+
+ return HP{
+ .val = p,
+ .off = in.off * val + e,
+ };
+}
+
+/// Split a double into two halves.
+/// @val: The double.
+/// @hi: The high bits.
+/// @lo: The low bits.
+fn split(val: f64, hi: *f64, lo: *f64) void {
+ hi.* = gethi(val);
+ lo.* = val - hi.*;
+}
+
+fn gethi(in: f64) f64 {
+ const bits = @bitCast(u64, in);
+ const new_bits = bits & 0xFFFFFFFFF8000000;
+ return @bitCast(f64, new_bits);
+}
+
+/// Normalize the number by factoring in the error.
+/// @hp: The float pair.
+fn hpNormalize(hp: *HP) void {
+ const val = hp.val;
+ hp.val += hp.off;
+ hp.off += val - hp.val;
+}
+
+/// Divide the high-precision number by ten.
+/// @hp: The high-precision number
+fn hpDiv10(hp: *HP) void {
+ var val = hp.val;
+
+ hp.val /= 10.0;
+ hp.off /= 10.0;
+
+ val -= hp.val * 8.0;
+ val -= hp.val * 2.0;
+
+ hp.off += val / 10.0;
+
+ hpNormalize(hp);
+}
+
+/// Multiply the high-precision number by ten.
+/// @hp: The high-precision number
+fn hpMul10(hp: *HP) void {
+ const val = hp.val;
+
+ hp.val *= 10.0;
+ hp.off *= 10.0;
+
+ var off = hp.val;
+ off -= val * 8.0;
+ off -= val * 2.0;
+
+ hp.off -= off;
+
+ hpNormalize(hp);
+}
+
+/// Integer conversion algorithm, guaranteed correct, optimal, and best.
+/// @val: The val.
+/// @buf: The output buffer.
+/// &return: The exponent.
+fn errolInt(val: f64, buffer: []u8) FloatDecimal {
+ const pow19 = u128(1e19);
+
+ assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
+
+ var mid = @floatToInt(u128, val);
+ var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
+ var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
+
+ if (@bitCast(u64, val) & 0x1 != 0) {
+ high -= 1;
+ } else {
+ low -= 1;
+ }
+
+ var l64 = @intCast(u64, low % pow19);
+ const lf = @intCast(u64, (low / pow19) % pow19);
+
+ var h64 = @intCast(u64, high % pow19);
+ const hf = @intCast(u64, (high / pow19) % pow19);
+
+ if (lf != hf) {
+ l64 = lf;
+ h64 = hf;
+ mid = mid / (pow19 / 10);
+ }
+
+ var mi: i32 = mismatch10(l64, h64);
+ var x: u64 = 1;
+ {
+ var i: i32 = @boolToInt(lf == hf);
+ while (i < mi) : (i += 1) {
+ x *= 10;
+ }
+ }
+ const m64 = @truncate(u64, @divTrunc(mid, x));
+
+ if (lf != hf) mi += 19;
+
+ var buf_index = u64toa(m64, buffer) - 1;
+
+ if (mi != 0) {
+ buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
+ } else {
+ buf_index += 1;
+ }
+
+ return FloatDecimal{
+ .digits = buffer[0..buf_index],
+ .exp = @intCast(i32, buf_index) + mi,
+ };
+}
+
+/// Fixed point conversion algorithm, guaranteed correct, optimal, and best.
+/// @val: The val.
+/// @buf: The output buffer.
+/// &return: The exponent.
+fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
+ assert((val >= 16.0) and (val < 9.007199254740992e15));
+
+ const u = @floatToInt(u64, val);
+ const n = @intToFloat(f64, u);
+
+ var mid = val - n;
+ var lo = ((fpprev(val) - n) + mid) / 2.0;
+ var hi = ((fpnext(val) - n) + mid) / 2.0;
+
+ var buf_index = u64toa(u, buffer);
+ var exp = @intCast(i32, buf_index);
+ var j = buf_index;
+ buffer[j] = 0;
+
+ if (mid != 0.0) {
+ while (mid != 0.0) {
+ lo *= 10.0;
+ const ldig = @floatToInt(i32, lo);
+ lo -= @intToFloat(f64, ldig);
+
+ mid *= 10.0;
+ const mdig = @floatToInt(i32, mid);
+ mid -= @intToFloat(f64, mdig);
+
+ hi *= 10.0;
+ const hdig = @floatToInt(i32, hi);
+ hi -= @intToFloat(f64, hdig);
+
+ buffer[j] = @intCast(u8, mdig + '0');
+ j += 1;
+
+ if (hdig != ldig or j > 50) break;
+ }
+
+ if (mid > 0.5) {
+ buffer[j - 1] += 1;
+ } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
+ buffer[j - 1] += 1;
+ }
+ } else {
+ while (buffer[j - 1] == '0') {
+ buffer[j - 1] = 0;
+ j -= 1;
+ }
+ }
+
+ buffer[j] = 0;
+
+ return FloatDecimal{
+ .digits = buffer[0..j],
+ .exp = exp,
+ };
+}
+
+fn fpnext(val: f64) f64 {
+ return @bitCast(f64, @bitCast(u64, val) +% 1);
+}
+
+fn fpprev(val: f64) f64 {
+ return @bitCast(f64, @bitCast(u64, val) -% 1);
+}
+
+pub const c_digits_lut = []u8{
+ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
+ '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
+ '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
+ '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
+ '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
+ '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
+ '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
+ '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
+ '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
+ '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
+ '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
+ '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
+ '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
+ '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
+ '9', '8', '9', '9',
+};
+
+fn u64toa(value_param: u64, buffer: []u8) usize {
+ var value = value_param;
+ const kTen8: u64 = 100000000;
+ const kTen9: u64 = kTen8 * 10;
+ const kTen10: u64 = kTen8 * 100;
+ const kTen11: u64 = kTen8 * 1000;
+ const kTen12: u64 = kTen8 * 10000;
+ const kTen13: u64 = kTen8 * 100000;
+ const kTen14: u64 = kTen8 * 1000000;
+ const kTen15: u64 = kTen8 * 10000000;
+ const kTen16: u64 = kTen8 * kTen8;
+
+ var buf_index: usize = 0;
+
+ if (value < kTen8) {
+ const v = @intCast(u32, value);
+ if (v < 10000) {
+ const d1: u32 = (v / 100) << 1;
+ const d2: u32 = (v % 100) << 1;
+
+ if (v >= 1000) {
+ buffer[buf_index] = c_digits_lut[d1];
+ buf_index += 1;
+ }
+ if (v >= 100) {
+ buffer[buf_index] = c_digits_lut[d1 + 1];
+ buf_index += 1;
+ }
+ if (v >= 10) {
+ buffer[buf_index] = c_digits_lut[d2];
+ buf_index += 1;
+ }
+ buffer[buf_index] = c_digits_lut[d2 + 1];
+ buf_index += 1;
+ } else {
+ // value = bbbbcccc
+ const b: u32 = v / 10000;
+ const c: u32 = v % 10000;
+
+ const d1: u32 = (b / 100) << 1;
+ const d2: u32 = (b % 100) << 1;
+
+ const d3: u32 = (c / 100) << 1;
+ const d4: u32 = (c % 100) << 1;
+
+ if (value >= 10000000) {
+ buffer[buf_index] = c_digits_lut[d1];
+ buf_index += 1;
+ }
+ if (value >= 1000000) {
+ buffer[buf_index] = c_digits_lut[d1 + 1];
+ buf_index += 1;
+ }
+ if (value >= 100000) {
+ buffer[buf_index] = c_digits_lut[d2];
+ buf_index += 1;
+ }
+ buffer[buf_index] = c_digits_lut[d2 + 1];
+ buf_index += 1;
+
+ buffer[buf_index] = c_digits_lut[d3];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d3 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d4];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d4 + 1];
+ buf_index += 1;
+ }
+ } else if (value < kTen16) {
+ const v0: u32 = @intCast(u32, value / kTen8);
+ const v1: u32 = @intCast(u32, value % kTen8);
+
+ const b0: u32 = v0 / 10000;
+ const c0: u32 = v0 % 10000;
+
+ const d1: u32 = (b0 / 100) << 1;
+ const d2: u32 = (b0 % 100) << 1;
+
+ const d3: u32 = (c0 / 100) << 1;
+ const d4: u32 = (c0 % 100) << 1;
+
+ const b1: u32 = v1 / 10000;
+ const c1: u32 = v1 % 10000;
+
+ const d5: u32 = (b1 / 100) << 1;
+ const d6: u32 = (b1 % 100) << 1;
+
+ const d7: u32 = (c1 / 100) << 1;
+ const d8: u32 = (c1 % 100) << 1;
+
+ if (value >= kTen15) {
+ buffer[buf_index] = c_digits_lut[d1];
+ buf_index += 1;
+ }
+ if (value >= kTen14) {
+ buffer[buf_index] = c_digits_lut[d1 + 1];
+ buf_index += 1;
+ }
+ if (value >= kTen13) {
+ buffer[buf_index] = c_digits_lut[d2];
+ buf_index += 1;
+ }
+ if (value >= kTen12) {
+ buffer[buf_index] = c_digits_lut[d2 + 1];
+ buf_index += 1;
+ }
+ if (value >= kTen11) {
+ buffer[buf_index] = c_digits_lut[d3];
+ buf_index += 1;
+ }
+ if (value >= kTen10) {
+ buffer[buf_index] = c_digits_lut[d3 + 1];
+ buf_index += 1;
+ }
+ if (value >= kTen9) {
+ buffer[buf_index] = c_digits_lut[d4];
+ buf_index += 1;
+ }
+ if (value >= kTen8) {
+ buffer[buf_index] = c_digits_lut[d4 + 1];
+ buf_index += 1;
+ }
+
+ buffer[buf_index] = c_digits_lut[d5];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d5 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d6];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d6 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d7];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d7 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d8];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d8 + 1];
+ buf_index += 1;
+ } else {
+ const a = @intCast(u32, value / kTen16); // 1 to 1844
+ value %= kTen16;
+
+ if (a < 10) {
+ buffer[buf_index] = '0' + @intCast(u8, a);
+ buf_index += 1;
+ } else if (a < 100) {
+ const i: u32 = a << 1;
+ buffer[buf_index] = c_digits_lut[i];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[i + 1];
+ buf_index += 1;
+ } else if (a < 1000) {
+ buffer[buf_index] = '0' + @intCast(u8, a / 100);
+ buf_index += 1;
+
+ const i: u32 = (a % 100) << 1;
+ buffer[buf_index] = c_digits_lut[i];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[i + 1];
+ buf_index += 1;
+ } else {
+ const i: u32 = (a / 100) << 1;
+ const j: u32 = (a % 100) << 1;
+ buffer[buf_index] = c_digits_lut[i];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[i + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[j];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[j + 1];
+ buf_index += 1;
+ }
+
+ const v0 = @intCast(u32, value / kTen8);
+ const v1 = @intCast(u32, value % kTen8);
+
+ const b0: u32 = v0 / 10000;
+ const c0: u32 = v0 % 10000;
+
+ const d1: u32 = (b0 / 100) << 1;
+ const d2: u32 = (b0 % 100) << 1;
+
+ const d3: u32 = (c0 / 100) << 1;
+ const d4: u32 = (c0 % 100) << 1;
+
+ const b1: u32 = v1 / 10000;
+ const c1: u32 = v1 % 10000;
+
+ const d5: u32 = (b1 / 100) << 1;
+ const d6: u32 = (b1 % 100) << 1;
+
+ const d7: u32 = (c1 / 100) << 1;
+ const d8: u32 = (c1 % 100) << 1;
+
+ buffer[buf_index] = c_digits_lut[d1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d1 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d2];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d2 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d3];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d3 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d4];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d4 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d5];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d5 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d6];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d6 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d7];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d7 + 1];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d8];
+ buf_index += 1;
+ buffer[buf_index] = c_digits_lut[d8 + 1];
+ buf_index += 1;
+ }
+
+ return buf_index;
+}
+
+fn fpeint(from: f64) u128 {
+ const bits = @bitCast(u64, from);
+ assert((bits & ((1 << 52) - 1)) == 0);
+
+ return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
+}
+
+/// Given two different integers with the same length in terms of the number
+/// of decimal digits, index the digits from the right-most position starting
+/// from zero, find the first index where the digits in the two integers
+/// divergent starting from the highest index.
+/// @a: Integer a.
+/// @b: Integer b.
+/// &returns: An index within [0, 19).
+fn mismatch10(a: u64, b: u64) i32 {
+ const pow10 = 10000000000;
+ const af = a / pow10;
+ const bf = b / pow10;
+
+ var i: i32 = 0;
+ var a_copy = a;
+ var b_copy = b;
+
+ if (af != bf) {
+ i = 10;
+ a_copy = af;
+ b_copy = bf;
+ }
+
+ while (true) : (i += 1) {
+ a_copy /= 10;
+ b_copy /= 10;
+
+ if (a_copy == b_copy) return i;
+ }
+}
diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig
deleted file mode 100644
index 0fdb1c4ab89b23dda123258f68b7b9cd94361e1d..0000000000000000000000000000000000000000
--- a/std/fmt/errol/index.zig
+++ /dev/null
@@ -1,704 +0,0 @@
-const std = @import("../../index.zig");
-const enum3 = @import("enum3.zig").enum3;
-const enum3_data = @import("enum3.zig").enum3_data;
-const lookup_table = @import("lookup.zig").lookup_table;
-const HP = @import("lookup.zig").HP;
-const math = std.math;
-const mem = std.mem;
-const assert = std.debug.assert;
-
-pub const FloatDecimal = struct {
- digits: []u8,
- exp: i32,
-};
-
-pub const RoundMode = enum {
- // Round only the fractional portion (e.g. 1234.23 has precision 2)
- Decimal,
- // Round the entire whole/fractional portion (e.g. 1.23423e3 has precision 5)
- Scientific,
-};
-
-/// Round a FloatDecimal as returned by errol3 to the specified fractional precision.
-/// All digits after the specified precision should be considered invalid.
-pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: RoundMode) void {
- // The round digit refers to the index which we should look at to determine
- // whether we need to round to match the specified precision.
- var round_digit: usize = 0;
-
- switch (mode) {
- RoundMode.Decimal => {
- if (float_decimal.exp >= 0) {
- round_digit = precision + @intCast(usize, float_decimal.exp);
- } else {
- // if a small negative exp, then adjust we need to offset by the number
- // of leading zeros that will occur.
- const min_exp_required = @intCast(usize, -float_decimal.exp);
- if (precision > min_exp_required) {
- round_digit = precision - min_exp_required;
- }
- }
- },
- RoundMode.Scientific => {
- round_digit = 1 + precision;
- },
- }
-
- // It suffices to look at just this digit. We don't round and propagate say 0.04999 to 0.05
- // first, and then to 0.1 in the case of a {.1} single precision.
-
- // Find the digit which will signify the round point and start rounding backwards.
- if (round_digit < float_decimal.digits.len and float_decimal.digits[round_digit] - '0' >= 5) {
- assert(round_digit >= 0);
-
- var i = round_digit;
- while (true) {
- if (i == 0) {
- // Rounded all the way past the start. This was of the form 9.999...
- // Slot the new digit in place and increase the exponent.
- float_decimal.exp += 1;
-
- // Re-size the buffer to use the reserved leading byte.
- const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
- float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
- float_decimal.digits[0] = '1';
- return;
- }
-
- i -= 1;
-
- const new_value = (float_decimal.digits[i] - '0' + 1) % 10;
- float_decimal.digits[i] = new_value + '0';
-
- // must continue rounding until non-9
- if (new_value != 0) {
- return;
- }
- }
- }
-}
-
-/// Corrected Errol3 double to ASCII conversion.
-pub fn errol3(value: f64, buffer: []u8) FloatDecimal {
- const bits = @bitCast(u64, value);
- const i = tableLowerBound(bits);
- if (i < enum3.len and enum3[i] == bits) {
- const data = enum3_data[i];
- const digits = buffer[1 .. data.str.len + 1];
- mem.copy(u8, digits, data.str);
- return FloatDecimal{
- .digits = digits,
- .exp = data.exp,
- };
- }
-
- return errol3u(value, buffer);
-}
-
-/// Uncorrected Errol3 double to ASCII conversion.
-fn errol3u(val: f64, buffer: []u8) FloatDecimal {
- // check if in integer or fixed range
- if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
- return errolInt(val, buffer);
- } else if (val >= 16.0 and val < 9.007199254740992e15) {
- return errolFixed(val, buffer);
- }
-
- // normalize the midpoint
-
- const e = math.frexp(val).exponent;
- var exp = @floatToInt(i16, math.floor(307 + @intToFloat(f64, e) * 0.30103));
- if (exp < 20) {
- exp = 20;
- } else if (@intCast(usize, exp) >= lookup_table.len) {
- exp = @intCast(i16, lookup_table.len - 1);
- }
-
- var mid = lookup_table[@intCast(usize, exp)];
- mid = hpProd(mid, val);
- const lten = lookup_table[@intCast(usize, exp)].val;
-
- exp -= 307;
-
- var ten: f64 = 1.0;
-
- while (mid.val > 10.0 or (mid.val == 10.0 and mid.off >= 0.0)) {
- exp += 1;
- hpDiv10(&mid);
- ten /= 10.0;
- }
-
- while (mid.val < 1.0 or (mid.val == 1.0 and mid.off < 0.0)) {
- exp -= 1;
- hpMul10(&mid);
- ten *= 10.0;
- }
-
- // compute boundaries
- var high = HP{
- .val = mid.val,
- .off = mid.off + (fpnext(val) - val) * lten * ten / 2.0,
- };
- var low = HP{
- .val = mid.val,
- .off = mid.off + (fpprev(val) - val) * lten * ten / 2.0,
- };
-
- hpNormalize(&high);
- hpNormalize(&low);
-
- // normalized boundaries
-
- while (high.val > 10.0 or (high.val == 10.0 and high.off >= 0.0)) {
- exp += 1;
- hpDiv10(&high);
- hpDiv10(&low);
- }
-
- while (high.val < 1.0 or (high.val == 1.0 and high.off < 0.0)) {
- exp -= 1;
- hpMul10(&high);
- hpMul10(&low);
- }
-
- // digit generation
-
- // We generate digits starting at index 1. If rounding a buffer later then it may be
- // required to generate a preceding digit in some cases (9.999) in which case we use
- // the 0-index for this extra digit.
- var buf_index: usize = 1;
- while (true) {
- var hdig = @floatToInt(u8, math.floor(high.val));
- if ((high.val == @intToFloat(f64, hdig)) and (high.off < 0)) hdig -= 1;
-
- var ldig = @floatToInt(u8, math.floor(low.val));
- if ((low.val == @intToFloat(f64, ldig)) and (low.off < 0)) ldig -= 1;
-
- if (ldig != hdig) break;
-
- buffer[buf_index] = hdig + '0';
- buf_index += 1;
- high.val -= @intToFloat(f64, hdig);
- low.val -= @intToFloat(f64, ldig);
- hpMul10(&high);
- hpMul10(&low);
- }
-
- const tmp = (high.val + low.val) / 2.0;
- var mdig = @floatToInt(u8, math.floor(tmp + 0.5));
- if ((@intToFloat(f64, mdig) - tmp) == 0.5 and (mdig & 0x1) != 0) mdig -= 1;
-
- buffer[buf_index] = mdig + '0';
- buf_index += 1;
-
- return FloatDecimal{
- .digits = buffer[1..buf_index],
- .exp = exp,
- };
-}
-
-fn tableLowerBound(k: u64) usize {
- var i = enum3.len;
- var j: usize = 0;
-
- while (j < enum3.len) {
- if (enum3[j] < k) {
- j = 2 * j + 2;
- } else {
- i = j;
- j = 2 * j + 1;
- }
- }
-
- return i;
-}
-
-/// Compute the product of an HP number and a double.
-/// @in: The HP number.
-/// @val: The double.
-/// &returns: The HP number.
-fn hpProd(in: HP, val: f64) HP {
- var hi: f64 = undefined;
- var lo: f64 = undefined;
- split(in.val, &hi, &lo);
-
- var hi2: f64 = undefined;
- var lo2: f64 = undefined;
- split(val, &hi2, &lo2);
-
- const p = in.val * val;
- const e = ((hi * hi2 - p) + lo * hi2 + hi * lo2) + lo * lo2;
-
- return HP{
- .val = p,
- .off = in.off * val + e,
- };
-}
-
-/// Split a double into two halves.
-/// @val: The double.
-/// @hi: The high bits.
-/// @lo: The low bits.
-fn split(val: f64, hi: *f64, lo: *f64) void {
- hi.* = gethi(val);
- lo.* = val - hi.*;
-}
-
-fn gethi(in: f64) f64 {
- const bits = @bitCast(u64, in);
- const new_bits = bits & 0xFFFFFFFFF8000000;
- return @bitCast(f64, new_bits);
-}
-
-/// Normalize the number by factoring in the error.
-/// @hp: The float pair.
-fn hpNormalize(hp: *HP) void {
- const val = hp.val;
- hp.val += hp.off;
- hp.off += val - hp.val;
-}
-
-/// Divide the high-precision number by ten.
-/// @hp: The high-precision number
-fn hpDiv10(hp: *HP) void {
- var val = hp.val;
-
- hp.val /= 10.0;
- hp.off /= 10.0;
-
- val -= hp.val * 8.0;
- val -= hp.val * 2.0;
-
- hp.off += val / 10.0;
-
- hpNormalize(hp);
-}
-
-/// Multiply the high-precision number by ten.
-/// @hp: The high-precision number
-fn hpMul10(hp: *HP) void {
- const val = hp.val;
-
- hp.val *= 10.0;
- hp.off *= 10.0;
-
- var off = hp.val;
- off -= val * 8.0;
- off -= val * 2.0;
-
- hp.off -= off;
-
- hpNormalize(hp);
-}
-
-/// Integer conversion algorithm, guaranteed correct, optimal, and best.
-/// @val: The val.
-/// @buf: The output buffer.
-/// &return: The exponent.
-fn errolInt(val: f64, buffer: []u8) FloatDecimal {
- const pow19 = u128(1e19);
-
- assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
-
- var mid = @floatToInt(u128, val);
- var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
- var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
-
- if (@bitCast(u64, val) & 0x1 != 0) {
- high -= 1;
- } else {
- low -= 1;
- }
-
- var l64 = @intCast(u64, low % pow19);
- const lf = @intCast(u64, (low / pow19) % pow19);
-
- var h64 = @intCast(u64, high % pow19);
- const hf = @intCast(u64, (high / pow19) % pow19);
-
- if (lf != hf) {
- l64 = lf;
- h64 = hf;
- mid = mid / (pow19 / 10);
- }
-
- var mi: i32 = mismatch10(l64, h64);
- var x: u64 = 1;
- {
- var i: i32 = @boolToInt(lf == hf);
- while (i < mi) : (i += 1) {
- x *= 10;
- }
- }
- const m64 = @truncate(u64, @divTrunc(mid, x));
-
- if (lf != hf) mi += 19;
-
- var buf_index = u64toa(m64, buffer) - 1;
-
- if (mi != 0) {
- buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
- } else {
- buf_index += 1;
- }
-
- return FloatDecimal{
- .digits = buffer[0..buf_index],
- .exp = @intCast(i32, buf_index) + mi,
- };
-}
-
-/// Fixed point conversion algorithm, guaranteed correct, optimal, and best.
-/// @val: The val.
-/// @buf: The output buffer.
-/// &return: The exponent.
-fn errolFixed(val: f64, buffer: []u8) FloatDecimal {
- assert((val >= 16.0) and (val < 9.007199254740992e15));
-
- const u = @floatToInt(u64, val);
- const n = @intToFloat(f64, u);
-
- var mid = val - n;
- var lo = ((fpprev(val) - n) + mid) / 2.0;
- var hi = ((fpnext(val) - n) + mid) / 2.0;
-
- var buf_index = u64toa(u, buffer);
- var exp = @intCast(i32, buf_index);
- var j = buf_index;
- buffer[j] = 0;
-
- if (mid != 0.0) {
- while (mid != 0.0) {
- lo *= 10.0;
- const ldig = @floatToInt(i32, lo);
- lo -= @intToFloat(f64, ldig);
-
- mid *= 10.0;
- const mdig = @floatToInt(i32, mid);
- mid -= @intToFloat(f64, mdig);
-
- hi *= 10.0;
- const hdig = @floatToInt(i32, hi);
- hi -= @intToFloat(f64, hdig);
-
- buffer[j] = @intCast(u8, mdig + '0');
- j += 1;
-
- if (hdig != ldig or j > 50) break;
- }
-
- if (mid > 0.5) {
- buffer[j - 1] += 1;
- } else if ((mid == 0.5) and (buffer[j - 1] & 0x1) != 0) {
- buffer[j - 1] += 1;
- }
- } else {
- while (buffer[j - 1] == '0') {
- buffer[j - 1] = 0;
- j -= 1;
- }
- }
-
- buffer[j] = 0;
-
- return FloatDecimal{
- .digits = buffer[0..j],
- .exp = exp,
- };
-}
-
-fn fpnext(val: f64) f64 {
- return @bitCast(f64, @bitCast(u64, val) +% 1);
-}
-
-fn fpprev(val: f64) f64 {
- return @bitCast(f64, @bitCast(u64, val) -% 1);
-}
-
-pub const c_digits_lut = []u8{
- '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
- '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
- '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
- '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
- '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
- '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
- '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
- '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
- '5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
- '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
- '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
- '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
- '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
- '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
- '9', '8', '9', '9',
-};
-
-fn u64toa(value_param: u64, buffer: []u8) usize {
- var value = value_param;
- const kTen8: u64 = 100000000;
- const kTen9: u64 = kTen8 * 10;
- const kTen10: u64 = kTen8 * 100;
- const kTen11: u64 = kTen8 * 1000;
- const kTen12: u64 = kTen8 * 10000;
- const kTen13: u64 = kTen8 * 100000;
- const kTen14: u64 = kTen8 * 1000000;
- const kTen15: u64 = kTen8 * 10000000;
- const kTen16: u64 = kTen8 * kTen8;
-
- var buf_index: usize = 0;
-
- if (value < kTen8) {
- const v = @intCast(u32, value);
- if (v < 10000) {
- const d1: u32 = (v / 100) << 1;
- const d2: u32 = (v % 100) << 1;
-
- if (v >= 1000) {
- buffer[buf_index] = c_digits_lut[d1];
- buf_index += 1;
- }
- if (v >= 100) {
- buffer[buf_index] = c_digits_lut[d1 + 1];
- buf_index += 1;
- }
- if (v >= 10) {
- buffer[buf_index] = c_digits_lut[d2];
- buf_index += 1;
- }
- buffer[buf_index] = c_digits_lut[d2 + 1];
- buf_index += 1;
- } else {
- // value = bbbbcccc
- const b: u32 = v / 10000;
- const c: u32 = v % 10000;
-
- const d1: u32 = (b / 100) << 1;
- const d2: u32 = (b % 100) << 1;
-
- const d3: u32 = (c / 100) << 1;
- const d4: u32 = (c % 100) << 1;
-
- if (value >= 10000000) {
- buffer[buf_index] = c_digits_lut[d1];
- buf_index += 1;
- }
- if (value >= 1000000) {
- buffer[buf_index] = c_digits_lut[d1 + 1];
- buf_index += 1;
- }
- if (value >= 100000) {
- buffer[buf_index] = c_digits_lut[d2];
- buf_index += 1;
- }
- buffer[buf_index] = c_digits_lut[d2 + 1];
- buf_index += 1;
-
- buffer[buf_index] = c_digits_lut[d3];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d3 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d4];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d4 + 1];
- buf_index += 1;
- }
- } else if (value < kTen16) {
- const v0: u32 = @intCast(u32, value / kTen8);
- const v1: u32 = @intCast(u32, value % kTen8);
-
- const b0: u32 = v0 / 10000;
- const c0: u32 = v0 % 10000;
-
- const d1: u32 = (b0 / 100) << 1;
- const d2: u32 = (b0 % 100) << 1;
-
- const d3: u32 = (c0 / 100) << 1;
- const d4: u32 = (c0 % 100) << 1;
-
- const b1: u32 = v1 / 10000;
- const c1: u32 = v1 % 10000;
-
- const d5: u32 = (b1 / 100) << 1;
- const d6: u32 = (b1 % 100) << 1;
-
- const d7: u32 = (c1 / 100) << 1;
- const d8: u32 = (c1 % 100) << 1;
-
- if (value >= kTen15) {
- buffer[buf_index] = c_digits_lut[d1];
- buf_index += 1;
- }
- if (value >= kTen14) {
- buffer[buf_index] = c_digits_lut[d1 + 1];
- buf_index += 1;
- }
- if (value >= kTen13) {
- buffer[buf_index] = c_digits_lut[d2];
- buf_index += 1;
- }
- if (value >= kTen12) {
- buffer[buf_index] = c_digits_lut[d2 + 1];
- buf_index += 1;
- }
- if (value >= kTen11) {
- buffer[buf_index] = c_digits_lut[d3];
- buf_index += 1;
- }
- if (value >= kTen10) {
- buffer[buf_index] = c_digits_lut[d3 + 1];
- buf_index += 1;
- }
- if (value >= kTen9) {
- buffer[buf_index] = c_digits_lut[d4];
- buf_index += 1;
- }
- if (value >= kTen8) {
- buffer[buf_index] = c_digits_lut[d4 + 1];
- buf_index += 1;
- }
-
- buffer[buf_index] = c_digits_lut[d5];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d5 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d6];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d6 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d7];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d7 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d8];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d8 + 1];
- buf_index += 1;
- } else {
- const a = @intCast(u32, value / kTen16); // 1 to 1844
- value %= kTen16;
-
- if (a < 10) {
- buffer[buf_index] = '0' + @intCast(u8, a);
- buf_index += 1;
- } else if (a < 100) {
- const i: u32 = a << 1;
- buffer[buf_index] = c_digits_lut[i];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[i + 1];
- buf_index += 1;
- } else if (a < 1000) {
- buffer[buf_index] = '0' + @intCast(u8, a / 100);
- buf_index += 1;
-
- const i: u32 = (a % 100) << 1;
- buffer[buf_index] = c_digits_lut[i];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[i + 1];
- buf_index += 1;
- } else {
- const i: u32 = (a / 100) << 1;
- const j: u32 = (a % 100) << 1;
- buffer[buf_index] = c_digits_lut[i];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[i + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[j];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[j + 1];
- buf_index += 1;
- }
-
- const v0 = @intCast(u32, value / kTen8);
- const v1 = @intCast(u32, value % kTen8);
-
- const b0: u32 = v0 / 10000;
- const c0: u32 = v0 % 10000;
-
- const d1: u32 = (b0 / 100) << 1;
- const d2: u32 = (b0 % 100) << 1;
-
- const d3: u32 = (c0 / 100) << 1;
- const d4: u32 = (c0 % 100) << 1;
-
- const b1: u32 = v1 / 10000;
- const c1: u32 = v1 % 10000;
-
- const d5: u32 = (b1 / 100) << 1;
- const d6: u32 = (b1 % 100) << 1;
-
- const d7: u32 = (c1 / 100) << 1;
- const d8: u32 = (c1 % 100) << 1;
-
- buffer[buf_index] = c_digits_lut[d1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d1 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d2];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d2 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d3];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d3 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d4];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d4 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d5];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d5 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d6];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d6 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d7];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d7 + 1];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d8];
- buf_index += 1;
- buffer[buf_index] = c_digits_lut[d8 + 1];
- buf_index += 1;
- }
-
- return buf_index;
-}
-
-fn fpeint(from: f64) u128 {
- const bits = @bitCast(u64, from);
- assert((bits & ((1 << 52) - 1)) == 0);
-
- return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
-}
-
-/// Given two different integers with the same length in terms of the number
-/// of decimal digits, index the digits from the right-most position starting
-/// from zero, find the first index where the digits in the two integers
-/// divergent starting from the highest index.
-/// @a: Integer a.
-/// @b: Integer b.
-/// &returns: An index within [0, 19).
-fn mismatch10(a: u64, b: u64) i32 {
- const pow10 = 10000000000;
- const af = a / pow10;
- const bf = b / pow10;
-
- var i: i32 = 0;
- var a_copy = a;
- var b_copy = b;
-
- if (af != bf) {
- i = 10;
- a_copy = af;
- b_copy = bf;
- }
-
- while (true) : (i += 1) {
- a_copy /= 10;
- b_copy /= 10;
-
- if (a_copy == b_copy) return i;
- }
-}
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
deleted file mode 100644
index 4f864b36626de9c733807b75eb9ce870b62c4df7..0000000000000000000000000000000000000000
--- a/std/fmt/index.zig
+++ /dev/null
@@ -1,1441 +0,0 @@
-const std = @import("../index.zig");
-const math = std.math;
-const debug = std.debug;
-const assert = debug.assert;
-const testing = std.testing;
-const mem = std.mem;
-const builtin = @import("builtin");
-const errol = @import("errol/index.zig");
-const lossyCast = std.math.lossyCast;
-
-const max_int_digits = 65;
-
-/// Renders fmt string with args, calling output with slices of bytes.
-/// If `output` returns an error, the error is returned from `format` and
-/// `output` is not called again.
-pub fn format(context: var, comptime Errors: type, output: fn (@typeOf(context), []const u8) Errors!void, comptime fmt: []const u8, args: ...) Errors!void {
- const State = enum {
- Start,
- OpenBrace,
- CloseBrace,
- FormatString,
- Pointer,
- };
-
- comptime var start_index = 0;
- comptime var state = State.Start;
- comptime var next_arg = 0;
-
- inline for (fmt) |c, i| {
- switch (state) {
- State.Start => switch (c) {
- '{' => {
- if (start_index < i) {
- try output(context, fmt[start_index..i]);
- }
- start_index = i;
- state = State.OpenBrace;
- },
-
- '}' => {
- if (start_index < i) {
- try output(context, fmt[start_index..i]);
- }
- state = State.CloseBrace;
- },
- else => {},
- },
- State.OpenBrace => switch (c) {
- '{' => {
- state = State.Start;
- start_index = i;
- },
- '}' => {
- try formatType(args[next_arg], fmt[0..0], context, Errors, output);
- next_arg += 1;
- state = State.Start;
- start_index = i + 1;
- },
- '*' => state = State.Pointer,
- else => {
- state = State.FormatString;
- },
- },
- State.CloseBrace => switch (c) {
- '}' => {
- state = State.Start;
- start_index = i;
- },
- else => @compileError("Single '}' encountered in format string"),
- },
- State.FormatString => switch (c) {
- '}' => {
- const s = start_index + 1;
- try formatType(args[next_arg], fmt[s..i], context, Errors, output);
- next_arg += 1;
- state = State.Start;
- start_index = i + 1;
- },
- else => {},
- },
- State.Pointer => switch (c) {
- '}' => {
- try output(context, @typeName(@typeOf(args[next_arg]).Child));
- try output(context, "@");
- try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
- next_arg += 1;
- state = State.Start;
- start_index = i + 1;
- },
- else => @compileError("Unexpected format character after '*'"),
- },
- }
- }
- comptime {
- if (args.len != next_arg) {
- @compileError("Unused arguments");
- }
- if (state != State.Start) {
- @compileError("Incomplete format string: " ++ fmt);
- }
- }
- if (start_index < fmt.len) {
- try output(context, fmt[start_index..]);
- }
-}
-
-pub fn formatType(
- value: var,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- const T = @typeOf(value);
- if (T == anyerror) {
- try output(context, "error.");
- return output(context, @errorName(value));
- }
- switch (@typeInfo(T)) {
- builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
- return formatValue(value, fmt, context, Errors, output);
- },
- builtin.TypeId.Void => {
- return output(context, "void");
- },
- builtin.TypeId.Bool => {
- return output(context, if (value) "true" else "false");
- },
- builtin.TypeId.Optional => {
- if (value) |payload| {
- return formatType(payload, fmt, context, Errors, output);
- } else {
- return output(context, "null");
- }
- },
- builtin.TypeId.ErrorUnion => {
- if (value) |payload| {
- return formatType(payload, fmt, context, Errors, output);
- } else |err| {
- return formatType(err, fmt, context, Errors, output);
- }
- },
- builtin.TypeId.ErrorSet => {
- try output(context, "error.");
- return output(context, @errorName(value));
- },
- builtin.TypeId.Promise => {
- return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
- },
- builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
- const has_cust_fmt = comptime cf: {
- const info = @typeInfo(T);
- const defs = switch (info) {
- builtin.TypeId.Struct => |s| s.defs,
- builtin.TypeId.Union => |u| u.defs,
- builtin.TypeId.Enum => |e| e.defs,
- else => unreachable,
- };
-
- for (defs) |def| {
- if (mem.eql(u8, def.name, "format")) {
- break :cf true;
- }
- }
- break :cf false;
- };
- if (has_cust_fmt) return value.format(fmt, context, Errors, output);
-
- try output(context, @typeName(T));
- switch (comptime @typeId(T)) {
- builtin.TypeId.Enum => {
- try output(context, ".");
- try formatType(@tagName(value), "", context, Errors, output);
- return;
- },
- builtin.TypeId.Struct => {
- comptime var field_i = 0;
- inline while (field_i < @memberCount(T)) : (field_i += 1) {
- if (field_i == 0) {
- try output(context, "{ .");
- } else {
- try output(context, ", .");
- }
- try output(context, @memberName(T, field_i));
- try output(context, " = ");
- try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output);
- }
- try output(context, " }");
- },
- builtin.TypeId.Union => {
- const info = @typeInfo(T).Union;
- if (info.tag_type) |UnionTagType| {
- try output(context, "{ .");
- try output(context, @tagName(UnionTagType(value)));
- try output(context, " = ");
- inline for (info.fields) |u_field| {
- if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
- try formatType(@field(value, u_field.name), "", context, Errors, output);
- }
- }
- try output(context, " }");
- } else {
- try format(context, Errors, output, "@{x}", @ptrToInt(&value));
- }
- },
- else => unreachable,
- }
- return;
- },
- builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
- builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
- builtin.TypeId.Array => |info| {
- if (info.child == u8) {
- return formatText(value, fmt, context, Errors, output);
- }
- return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
- },
- builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
- return formatType(value.*, fmt, context, Errors, output);
- },
- else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
- },
- builtin.TypeInfo.Pointer.Size.Many => {
- if (ptr_info.child == u8) {
- if (fmt.len > 0 and fmt[0] == 's') {
- const len = std.cstr.len(value);
- return formatText(value[0..len], fmt, context, Errors, output);
- }
- }
- return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
- },
- builtin.TypeInfo.Pointer.Size.Slice => {
- if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
- return formatText(value, fmt, context, Errors, output);
- }
- const casted_value = ([]const u8)(value);
- return output(context, casted_value);
- },
- builtin.TypeInfo.Pointer.Size.C => {
- return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
- },
- },
- builtin.TypeId.Array => |info| {
- if (info.child == u8) {
- return formatText(value, fmt, context, Errors, output);
- }
- return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
- },
- builtin.TypeId.Fn => {
- return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
- },
- else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
- }
-}
-
-fn formatValue(
- value: var,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- if (fmt.len > 0) {
- if (fmt[0] == 'B') {
- comptime var width: ?usize = null;
- if (fmt.len > 1) {
- if (fmt[1] == 'i') {
- if (fmt.len > 2) width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
- return formatBytes(value, width, 1024, context, Errors, output);
- }
- width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
- }
- return formatBytes(value, width, 1000, context, Errors, output);
- }
- }
-
- const T = @typeOf(value);
- switch (@typeId(T)) {
- builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
- builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
- builtin.TypeId.ComptimeInt => {
- const Int = math.IntFittingRange(value, value);
- return formatIntValue(Int(value), fmt, context, Errors, output);
- },
- else => comptime unreachable,
- }
-}
-
-pub fn formatIntValue(
- value: var,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- comptime var radix = 10;
- comptime var uppercase = false;
- comptime var width = 0;
- if (fmt.len > 0) {
- switch (fmt[0]) {
- 'c' => {
- if (@typeOf(value).bit_count <= 8) {
- if (fmt.len > 1)
- @compileError("Unknown format character: " ++ []u8{fmt[1]});
- return formatAsciiChar(u8(value), context, Errors, output);
- }
- },
- 'b' => {
- radix = 2;
- uppercase = false;
- width = 0;
- },
- 'd' => {
- radix = 10;
- uppercase = false;
- width = 0;
- },
- 'x' => {
- radix = 16;
- uppercase = false;
- width = 0;
- },
- 'X' => {
- radix = 16;
- uppercase = true;
- width = 0;
- },
- else => @compileError("Unknown format character: " ++ []u8{fmt[0]}),
- }
- if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
- }
- return formatInt(value, radix, uppercase, width, context, Errors, output);
-}
-
-fn formatFloatValue(
- value: var,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- comptime var width: ?usize = null;
- comptime var float_fmt = 'e';
- if (fmt.len > 0) {
- float_fmt = fmt[0];
- if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
- }
-
- switch (float_fmt) {
- 'e' => try formatFloatScientific(value, width, context, Errors, output),
- '.' => try formatFloatDecimal(value, width, context, Errors, output),
- else => @compileError("Unknown format character: " ++ []u8{float_fmt}),
- }
-}
-
-pub fn formatText(
- bytes: []const u8,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- if (fmt.len > 0) {
- if (fmt[0] == 's') {
- comptime var width = 0;
- if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
- return formatBuf(bytes, width, context, Errors, output);
- } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
- for (bytes) |c| {
- try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
- }
- return;
- } else @compileError("Unknown format character: " ++ []u8{fmt[0]});
- }
- return output(context, bytes);
-}
-
-pub fn formatAsciiChar(
- c: u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- return output(context, (*[1]u8)(&c)[0..]);
-}
-
-pub fn formatBuf(
- buf: []const u8,
- width: usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- try output(context, buf);
-
- var leftover_padding = if (width > buf.len) (width - buf.len) else return;
- const pad_byte: u8 = ' ';
- while (leftover_padding > 0) : (leftover_padding -= 1) {
- try output(context, (*[1]u8)(&pad_byte)[0..1]);
- }
-}
-
-// Print a float in scientific notation to the specified precision. Null uses full precision.
-// It should be the case that every full precision, printed value can be re-parsed back to the
-// same type unambiguously.
-pub fn formatFloatScientific(
- value: var,
- maybe_precision: ?usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- var x = @floatCast(f64, value);
-
- // Errol doesn't handle these special cases.
- if (math.signbit(x)) {
- try output(context, "-");
- x = -x;
- }
-
- if (math.isNan(x)) {
- return output(context, "nan");
- }
- if (math.isPositiveInf(x)) {
- return output(context, "inf");
- }
- if (x == 0.0) {
- try output(context, "0");
-
- if (maybe_precision) |precision| {
- if (precision != 0) {
- try output(context, ".");
- var i: usize = 0;
- while (i < precision) : (i += 1) {
- try output(context, "0");
- }
- }
- } else {
- try output(context, ".0");
- }
-
- try output(context, "e+00");
- return;
- }
-
- var buffer: [32]u8 = undefined;
- var float_decimal = errol.errol3(x, buffer[0..]);
-
- if (maybe_precision) |precision| {
- errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
-
- try output(context, float_decimal.digits[0..1]);
-
- // {e0} case prints no `.`
- if (precision != 0) {
- try output(context, ".");
-
- var printed: usize = 0;
- if (float_decimal.digits.len > 1) {
- const num_digits = math.min(float_decimal.digits.len, precision + 1);
- try output(context, float_decimal.digits[1..num_digits]);
- printed += num_digits - 1;
- }
-
- while (printed < precision) : (printed += 1) {
- try output(context, "0");
- }
- }
- } else {
- try output(context, float_decimal.digits[0..1]);
- try output(context, ".");
- if (float_decimal.digits.len > 1) {
- const num_digits = if (@typeOf(value) == f32) math.min(usize(9), float_decimal.digits.len) else float_decimal.digits.len;
-
- try output(context, float_decimal.digits[1..num_digits]);
- } else {
- try output(context, "0");
- }
- }
-
- try output(context, "e");
- const exp = float_decimal.exp - 1;
-
- if (exp >= 0) {
- try output(context, "+");
- if (exp > -10 and exp < 10) {
- try output(context, "0");
- }
- try formatInt(exp, 10, false, 0, context, Errors, output);
- } else {
- try output(context, "-");
- if (exp > -10 and exp < 10) {
- try output(context, "0");
- }
- try formatInt(-exp, 10, false, 0, context, Errors, output);
- }
-}
-
-// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
-// By default floats are printed at full precision (no rounding).
-pub fn formatFloatDecimal(
- value: var,
- maybe_precision: ?usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- var x = f64(value);
-
- // Errol doesn't handle these special cases.
- if (math.signbit(x)) {
- try output(context, "-");
- x = -x;
- }
-
- if (math.isNan(x)) {
- return output(context, "nan");
- }
- if (math.isPositiveInf(x)) {
- return output(context, "inf");
- }
- if (x == 0.0) {
- try output(context, "0");
-
- if (maybe_precision) |precision| {
- if (precision != 0) {
- try output(context, ".");
- var i: usize = 0;
- while (i < precision) : (i += 1) {
- try output(context, "0");
- }
- } else {
- try output(context, ".0");
- }
- } else {
- try output(context, "0");
- }
-
- return;
- }
-
- // non-special case, use errol3
- var buffer: [32]u8 = undefined;
- var float_decimal = errol.errol3(x, buffer[0..]);
-
- if (maybe_precision) |precision| {
- errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
-
- // exp < 0 means the leading is always 0 as errol result is normalized.
- var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
-
- // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
- var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
-
- if (num_digits_whole > 0) {
- // We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
-
- var i = num_digits_whole_no_pad;
- while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
- }
- } else {
- try output(context, "0");
- }
-
- // {.0} special case doesn't want a trailing '.'
- if (precision == 0) {
- return;
- }
-
- try output(context, ".");
-
- // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
- var printed: usize = 0;
-
- // Zero-fill until we reach significant digits or run out of precision.
- if (float_decimal.exp <= 0) {
- const zero_digit_count = @intCast(usize, -float_decimal.exp);
- const zeros_to_print = math.min(zero_digit_count, precision);
-
- var i: usize = 0;
- while (i < zeros_to_print) : (i += 1) {
- try output(context, "0");
- printed += 1;
- }
-
- if (printed >= precision) {
- return;
- }
- }
-
- // Remaining fractional portion, zero-padding if insufficient.
- assert(precision >= printed);
- if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
- try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
- return;
- } else {
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
- printed += float_decimal.digits.len - num_digits_whole_no_pad;
-
- while (printed < precision) : (printed += 1) {
- try output(context, "0");
- }
- }
- } else {
- // exp < 0 means the leading is always 0 as errol result is normalized.
- var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
-
- // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
- var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
-
- if (num_digits_whole > 0) {
- // We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
-
- var i = num_digits_whole_no_pad;
- while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
- }
- } else {
- try output(context, "0");
- }
-
- // Omit `.` if no fractional portion
- if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
- return;
- }
-
- try output(context, ".");
-
- // Zero-fill until we reach significant digits or run out of precision.
- if (float_decimal.exp < 0) {
- const zero_digit_count = @intCast(usize, -float_decimal.exp);
-
- var i: usize = 0;
- while (i < zero_digit_count) : (i += 1) {
- try output(context, "0");
- }
- }
-
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
- }
-}
-
-pub fn formatBytes(
- value: var,
- width: ?usize,
- comptime radix: usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- if (value == 0) {
- return output(context, "0B");
- }
-
- const mags_si = " kMGTPEZY";
- const mags_iec = " KMGTPEZY";
- const magnitude = switch (radix) {
- 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
- 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
- else => unreachable,
- };
- const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
- const suffix = switch (radix) {
- 1000 => mags_si[magnitude],
- 1024 => mags_iec[magnitude],
- else => unreachable,
- };
-
- try formatFloatDecimal(new_value, width, context, Errors, output);
-
- if (suffix == ' ') {
- return output(context, "B");
- }
-
- const buf = switch (radix) {
- 1000 => []u8{ suffix, 'B' },
- 1024 => []u8{ suffix, 'i', 'B' },
- else => unreachable,
- };
- return output(context, buf);
-}
-
-pub fn formatInt(
- value: var,
- base: u8,
- uppercase: bool,
- width: usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- if (@typeOf(value).is_signed) {
- return formatIntSigned(value, base, uppercase, width, context, Errors, output);
- } else {
- return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
- }
-}
-
-fn formatIntSigned(
- value: var,
- base: u8,
- uppercase: bool,
- width: usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- const uint = @IntType(false, @typeOf(value).bit_count);
- if (value < 0) {
- const minus_sign: u8 = '-';
- try output(context, (*[1]u8)(&minus_sign)[0..]);
- const new_value = @intCast(uint, -(value + 1)) + 1;
- const new_width = if (width == 0) 0 else (width - 1);
- return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
- } else if (width == 0) {
- return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
- } else {
- const plus_sign: u8 = '+';
- try output(context, (*[1]u8)(&plus_sign)[0..]);
- const new_value = @intCast(uint, value);
- const new_width = if (width == 0) 0 else (width - 1);
- return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
- }
-}
-
-fn formatIntUnsigned(
- value: var,
- base: u8,
- uppercase: bool,
- width: usize,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
-) Errors!void {
- // max_int_digits accounts for the minus sign. when printing an unsigned
- // number we don't need to do that.
- var buf: [max_int_digits - 1]u8 = undefined;
- const min_int_bits = comptime math.max(@typeOf(value).bit_count, @typeOf(base).bit_count);
- const MinInt = @IntType(@typeOf(value).is_signed, min_int_bits);
- var a: MinInt = value;
- var index: usize = buf.len;
-
- while (true) {
- const digit = a % base;
- index -= 1;
- buf[index] = digitToChar(@intCast(u8, digit), uppercase);
- a /= base;
- if (a == 0) break;
- }
-
- const digits_buf = buf[index..];
- const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
-
- if (padding > index) {
- const zero_byte: u8 = '0';
- var leftover_padding = padding - index;
- while (true) {
- try output(context, (*[1]u8)(&zero_byte)[0..]);
- leftover_padding -= 1;
- if (leftover_padding == 0) break;
- }
- mem.set(u8, buf[0..index], '0');
- return output(context, buf);
- } else {
- const padded_buf = buf[index - padding ..];
- mem.set(u8, padded_buf[0..padding], '0');
- return output(context, padded_buf);
- }
-}
-
-pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: usize) usize {
- var context = FormatIntBuf{
- .out_buf = out_buf,
- .index = 0,
- };
- formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
- return context.index;
-}
-const FormatIntBuf = struct {
- out_buf: []u8,
- index: usize,
-};
-fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
- mem.copy(u8, context.out_buf[context.index..], bytes);
- context.index += bytes.len;
-}
-
-pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
- if (!T.is_signed) return parseUnsigned(T, buf, radix);
- if (buf.len == 0) return T(0);
- if (buf[0] == '-') {
- return math.negate(try parseUnsigned(T, buf[1..], radix));
- } else if (buf[0] == '+') {
- return parseUnsigned(T, buf[1..], radix);
- } else {
- return parseUnsigned(T, buf, radix);
- }
-}
-
-test "fmt.parseInt" {
- testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
- testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
- testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
- testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
-}
-
-const ParseUnsignedError = error{
- /// The result cannot fit in the type specified
- Overflow,
-
- /// The input had a byte that was not a digit
- InvalidCharacter,
-};
-
-pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
- var x: T = 0;
-
- for (buf) |c| {
- const digit = try charToDigit(c, radix);
-
- if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
- x = try math.add(T, x, try math.cast(T, digit));
- }
-
- return x;
-}
-
-test "fmt.parseUnsigned" {
- testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
- testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
- testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
-
- testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
- testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
-
- testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
-
- testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
- testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
-
- testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
- testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
-
- testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
-
- // these numbers should fit even though the radix itself doesn't fit in the destination type
- testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
- testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
- testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
- testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
- testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
- testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
-}
-
-pub const parseFloat = @import("parse_float.zig").parseFloat;
-
-test "fmt.parseFloat" {
- _ = @import("parse_float.zig");
-}
-
-pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
- const value = switch (c) {
- '0'...'9' => c - '0',
- 'A'...'Z' => c - 'A' + 10,
- 'a'...'z' => c - 'a' + 10,
- else => return error.InvalidCharacter,
- };
-
- if (value >= radix) return error.InvalidCharacter;
-
- return value;
-}
-
-fn digitToChar(digit: u8, uppercase: bool) u8 {
- return switch (digit) {
- 0...9 => digit + '0',
- 10...35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
- else => unreachable,
- };
-}
-
-const BufPrintContext = struct {
- remaining: []u8,
-};
-
-fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
- if (context.remaining.len < bytes.len) return error.BufferTooSmall;
- mem.copy(u8, context.remaining, bytes);
- context.remaining = context.remaining[bytes.len..];
-}
-
-pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
- var context = BufPrintContext{ .remaining = buf };
- try format(&context, error{BufferTooSmall}, bufPrintWrite, fmt, args);
- return buf[0 .. buf.len - context.remaining.len];
-}
-
-pub const AllocPrintError = error{OutOfMemory};
-
-pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
- var size: usize = 0;
- format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
- const buf = try allocator.alloc(u8, size);
- return bufPrint(buf, fmt, args) catch |err| switch (err) {
- error.BufferTooSmall => unreachable, // we just counted the size above
- };
-}
-
-fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
- size.* += bytes.len;
-}
-
-test "buf print int" {
- var buffer: [max_int_digits]u8 = undefined;
- const buf = buffer[0..];
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E"));
-
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678"));
-
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234"));
-
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42"));
-}
-
-fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 {
- return buf[0..formatIntBuf(buf, value, base, uppercase, width)];
-}
-
-test "parse u64 digit too big" {
- _ = parseUnsigned(u64, "123a", 10) catch |err| {
- if (err == error.InvalidCharacter) return;
- unreachable;
- };
- unreachable;
-}
-
-test "parse unsigned comptime" {
- comptime {
- testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
- }
-}
-
-test "fmt.format" {
- {
- const value: ?i32 = 1234;
- try testFmt("optional: 1234\n", "optional: {}\n", value);
- }
- {
- const value: ?i32 = null;
- try testFmt("optional: null\n", "optional: {}\n", value);
- }
- {
- const value: anyerror!i32 = 1234;
- try testFmt("error union: 1234\n", "error union: {}\n", value);
- }
- {
- const value: anyerror!i32 = error.InvalidChar;
- try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
- }
- {
- const value: u3 = 0b101;
- try testFmt("u3: 5\n", "u3: {}\n", value);
- }
- {
- const value: u8 = 'a';
- try testFmt("u8: a\n", "u8: {c}\n", value);
- }
- {
- const value: u8 = 0b1100;
- try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
- }
- {
- var buf1: [32]u8 = undefined;
- var context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
- var res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "1234"));
-
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
- res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "a"));
-
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
- res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "1100"));
- }
- {
- const value: [3]u8 = "abc";
- try testFmt("array: abc\n", "array: {}\n", value);
- try testFmt("array: abc\n", "array: {}\n", &value);
-
- var buf: [100]u8 = undefined;
- try testFmt(
- try bufPrint(buf[0..], "array: [3]u8@{x}\n", @ptrToInt(&value)),
- "array: {*}\n",
- &value,
- );
- }
- {
- const value: []const u8 = "abc";
- try testFmt("slice: abc\n", "slice: {}\n", value);
- }
- {
- const value = @intToPtr(*i32, 0xdeadbeef);
- try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
- try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
- }
- try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
- try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
- try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
- try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");
- try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
- try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
- {
- const Struct = struct {
- field: u8,
- };
- const value = Struct{ .field = 42 };
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", value);
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", &value);
- }
- {
- const Struct = struct {
- a: u0,
- b: u1,
- };
- const value = Struct{ .a = 0, .b = 1 };
- try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", value);
- }
- {
- const Enum = enum {
- One,
- Two,
- };
- const value = Enum.Two;
- try testFmt("enum: Enum.Two\n", "enum: {}\n", value);
- try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = 1.34;
- const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
- testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = 12.34;
- const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
- testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = -12.34e10;
- const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
- testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
- }
- {
- // This fails on release due to a minor rounding difference.
- // --release-fast outputs 9.999960000000001e-40 vs. the expected.
- // TODO fix this, it should be the same in Debug and ReleaseFast
- if (builtin.mode == builtin.Mode.Debug) {
- var buf1: [32]u8 = undefined;
- const value: f64 = 9.999960e-40;
- const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
- }
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 1.409706e-42;
- const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = @bitCast(f32, u32(814313563));
- const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = @bitCast(f32, u32(1006632960));
- const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
- }
- {
- // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
- // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
- var buf1: [32]u8 = undefined;
- const value: f64 = @bitCast(f32, u32(1203982400));
- const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
- testing.expect(mem.eql(u8, result, "f64: nan\n"));
- }
- if (builtin.arch != builtin.Arch.arm) {
- // negative nan is not defined by IEE 754,
- // and ARM thus normalizes it to positive nan
- var buf1: [32]u8 = undefined;
- const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
- testing.expect(mem.eql(u8, result, "f64: -nan\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
- testing.expect(mem.eql(u8, result, "f64: inf\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
- testing.expect(mem.eql(u8, result, "f64: -inf\n"));
- }
- {
- var buf1: [64]u8 = undefined;
- const value: f64 = 1.52314e+29;
- const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = 1.1234;
- const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
- testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = 1234.567;
- const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
- testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = -11.1234;
- const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
- // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
- // -11.12339... is rounded back up to -11.1234
- testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f32 = 91.12345;
- const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 91.12345678901235;
- const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 0.0;
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 5.700;
- const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 6\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 9.999;
- const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 1.0;
- const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 0.0003;
- const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 1.40130e-45;
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = 9.999960e-40;
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
- }
- // libc checks
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(916964781)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(925353389)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(1036831278)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(1065353133)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
- }
- {
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(1092616192)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
- }
- // libc differences
- {
- var buf1: [32]u8 = undefined;
- // This is 0.015625 exactly according to gdb. We thus round down,
- // however glibc rounds up for some reason. This occurs for all
- // floats of the form x.yyyy25 on a precision point.
- const value: f64 = f64(@bitCast(f32, u32(1015021568)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
- }
- // std-windows-x86_64-Debug-bare test case fails
- {
- // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
- // also rounds to 630 so I'm inclined to believe libc is not
- // optimal here.
- var buf1: [32]u8 = undefined;
- const value: f64 = f64(@bitCast(f32, u32(1518338049)));
- const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
- testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
- }
- //custom type format
- {
- const Vec2 = struct {
- const SelfType = @This();
- x: f32,
- y: f32,
-
- pub fn format(
- self: SelfType,
- comptime fmt: []const u8,
- context: var,
- comptime Errors: type,
- output: fn (@typeOf(context), []const u8) Errors!void,
- ) Errors!void {
- switch (fmt.len) {
- 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
- 1 => switch (fmt[0]) {
- //point format
- 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
- //dimension format
- 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
- else => unreachable,
- },
- else => unreachable,
- }
- }
- };
-
- var buf1: [32]u8 = undefined;
- var value = Vec2{
- .x = 10.2,
- .y = 2.22,
- };
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", &value);
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", &value);
-
- // same thing but not passing a pointer
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", value);
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
- }
- //struct format
- {
- const S = struct {
- a: u32,
- b: anyerror,
- };
-
- const inst = S{
- .a = 456,
- .b = error.Unused,
- };
-
- try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
- }
- //union format
- {
- const TU = union(enum) {
- float: f32,
- int: u32,
- };
-
- const UU = union {
- float: f32,
- int: u32,
- };
-
- const EU = extern union {
- float: f32,
- int: u32,
- };
-
- const tu_inst = TU{ .int = 123 };
- const uu_inst = UU{ .int = 456 };
- const eu_inst = EU{ .float = 321.123 };
-
- try testFmt("TU{ .int = 123 }", "{}", tu_inst);
-
- var buf: [100]u8 = undefined;
- const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
- testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
-
- const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
- testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
- }
- //enum format
- {
- const E = enum {
- One,
- Two,
- Three,
- };
-
- const inst = E.Two;
-
- try testFmt("E.Two", "{}", inst);
- }
- //print bytes as hex
- {
- const some_bytes = "\xCA\xFE\xBA\xBE";
- try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
- try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
- //Test Slices
- try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", some_bytes[0..2]);
- try testFmt("lowercase: babe\n", "lowercase: {x}\n", some_bytes[2..]);
- const bytes_with_zeros = "\x00\x0E\xBA\xBE";
- try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", bytes_with_zeros);
- }
-}
-
-fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
- var buf: [100]u8 = undefined;
- const result = try bufPrint(buf[0..], template, args);
- if (mem.eql(u8, result, expected)) return;
-
- std.debug.warn("\n====== expected this output: =========\n");
- std.debug.warn("{}", expected);
- std.debug.warn("\n======== instead found this: =========\n");
- std.debug.warn("{}", result);
- std.debug.warn("\n======================================\n");
- return error.TestFailed;
-}
-
-pub fn trim(buf: []const u8) []const u8 {
- var start: usize = 0;
- while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
-
- var end: usize = buf.len;
- while (true) {
- if (end > start) {
- const new_end = end - 1;
- if (isWhiteSpace(buf[new_end])) {
- end = new_end;
- continue;
- }
- }
- break;
- }
- return buf[start..end];
-}
-
-test "fmt.trim" {
- testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
- testing.expect(mem.eql(u8, "", trim(" ")));
- testing.expect(mem.eql(u8, "", trim("")));
- testing.expect(mem.eql(u8, "abc", trim(" abc")));
- testing.expect(mem.eql(u8, "abc", trim("abc ")));
-}
-
-pub fn isWhiteSpace(byte: u8) bool {
- return switch (byte) {
- ' ', '\t', '\n', '\r' => true,
- else => false,
- };
-}
-
-pub fn hexToBytes(out: []u8, input: []const u8) !void {
- if (out.len * 2 < input.len)
- return error.InvalidLength;
-
- var in_i: usize = 0;
- while (in_i != input.len) : (in_i += 2) {
- const hi = try charToDigit(input[in_i], 16);
- const lo = try charToDigit(input[in_i + 1], 16);
- out[in_i / 2] = (hi << 4) | lo;
- }
-}
-
-test "fmt.hexToBytes" {
- const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
- var pb: [32]u8 = undefined;
- try hexToBytes(pb[0..], test_hex_str);
- try testFmt(test_hex_str, "{X}", pb);
-}
diff --git a/std/fmt/parse_float.zig b/std/fmt/parse_float.zig
index de9619efe2b131eb43ba52484c9c3cf4f8efebbd..c13977dc4254bc1128f1b11c0e59a60ce174da72 100644
--- a/std/fmt/parse_float.zig
+++ b/std/fmt/parse_float.zig
@@ -29,7 +29,7 @@
// - Only supports round-to-zero
// - Does not handle denormals
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const max_digits = 25;
diff --git a/std/hash.zig b/std/hash.zig
new file mode 100644
index 0000000000000000000000000000000000000000..19ee62824d93efe0a69c980ae01c57ad54e61148
--- /dev/null
+++ b/std/hash.zig
@@ -0,0 +1,22 @@
+const adler = @import("hash/adler.zig");
+pub const Adler32 = adler.Adler32;
+
+// pub for polynomials + generic crc32 construction
+pub const crc = @import("hash/crc.zig");
+pub const Crc32 = crc.Crc32;
+
+const fnv = @import("hash/fnv.zig");
+pub const Fnv1a_32 = fnv.Fnv1a_32;
+pub const Fnv1a_64 = fnv.Fnv1a_64;
+pub const Fnv1a_128 = fnv.Fnv1a_128;
+
+const siphash = @import("hash/siphash.zig");
+pub const SipHash64 = siphash.SipHash64;
+pub const SipHash128 = siphash.SipHash128;
+
+test "hash" {
+ _ = @import("hash/adler.zig");
+ _ = @import("hash/crc.zig");
+ _ = @import("hash/fnv.zig");
+ _ = @import("hash/siphash.zig");
+}
diff --git a/std/hash/adler.zig b/std/hash/adler.zig
index 78f960367a546336c325ea976169d413bd76bc07..e95203cc6c3e1a435363b60e3751346ec6ad3d74 100644
--- a/std/hash/adler.zig
+++ b/std/hash/adler.zig
@@ -3,7 +3,7 @@
// https://tools.ietf.org/html/rfc1950#section-9
// https://github.com/madler/zlib/blob/master/adler32.c
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const testing = std.testing;
pub const Adler32 = struct {
diff --git a/std/hash/crc.zig b/std/hash/crc.zig
index 9bea358bf15db81fa8639fc271d477294d262586..53b4262c93599f70ae07bb89a6710ba5740d0f0f 100644
--- a/std/hash/crc.zig
+++ b/std/hash/crc.zig
@@ -5,7 +5,7 @@
// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
// still moderately fast just slow relative to the slicing approach.
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const debug = std.debug;
const testing = std.testing;
diff --git a/std/hash/fnv.zig b/std/hash/fnv.zig
index 6876b636f67852d58cb42e276a5356a4d419b98c..8094134e193e5d9588f67040ce569080eb50b185 100644
--- a/std/hash/fnv.zig
+++ b/std/hash/fnv.zig
@@ -4,7 +4,7 @@
//
// https://tools.ietf.org/html/draft-eastlake-fnv-14
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const testing = std.testing;
pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5);
diff --git a/std/hash/index.zig b/std/hash/index.zig
deleted file mode 100644
index 8cce35f3c50ea0f3d8160cbdeb606555442821b8..0000000000000000000000000000000000000000
--- a/std/hash/index.zig
+++ /dev/null
@@ -1,22 +0,0 @@
-const adler = @import("adler.zig");
-pub const Adler32 = adler.Adler32;
-
-// pub for polynomials + generic crc32 construction
-pub const crc = @import("crc.zig");
-pub const Crc32 = crc.Crc32;
-
-const fnv = @import("fnv.zig");
-pub const Fnv1a_32 = fnv.Fnv1a_32;
-pub const Fnv1a_64 = fnv.Fnv1a_64;
-pub const Fnv1a_128 = fnv.Fnv1a_128;
-
-const siphash = @import("siphash.zig");
-pub const SipHash64 = siphash.SipHash64;
-pub const SipHash128 = siphash.SipHash128;
-
-test "hash" {
- _ = @import("adler.zig");
- _ = @import("crc.zig");
- _ = @import("fnv.zig");
- _ = @import("siphash.zig");
-}
diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig
index c9a6128d35b7dab34fd21986b63dad3df5f54880..77194c3e037ea7159eb4c5b8783bdb6f3d126ddc 100644
--- a/std/hash/siphash.zig
+++ b/std/hash/siphash.zig
@@ -5,7 +5,7 @@
//
// https://131002.net/siphash/
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const math = std.math;
diff --git a/std/hash_map.zig b/std/hash_map.zig
index 4519890bb75b06ce289d46a45cb4f0d43f375f8e..d31fcdb59764e2c61784ceec2e2cd578354c0d73 100644
--- a/std/hash_map.zig
+++ b/std/hash_map.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
@@ -486,7 +486,6 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng),
builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),
- builtin.TypeId.Namespace,
builtin.TypeId.BoundFn,
builtin.TypeId.ComptimeFloat,
builtin.TypeId.ComptimeInt,
@@ -532,7 +531,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
builtin.TypeId.Float,
builtin.TypeId.ComptimeFloat,
builtin.TypeId.ComptimeInt,
- builtin.TypeId.Namespace,
builtin.TypeId.Promise,
builtin.TypeId.Enum,
builtin.TypeId.BoundFn,
diff --git a/std/heap.zig b/std/heap.zig
index e257977f9d72e5d3195aafac1a9e0224e6daae64..e03e77a39cb38bc9c20c7158730032ba8d8d9710 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
diff --git a/std/index.zig b/std/index.zig
deleted file mode 100644
index f8c1b065e9bd57dadc99e5efb192122c2a402a01..0000000000000000000000000000000000000000
--- a/std/index.zig
+++ /dev/null
@@ -1,95 +0,0 @@
-pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
-pub const ArrayList = @import("array_list.zig").ArrayList;
-pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;
-pub const BufMap = @import("buf_map.zig").BufMap;
-pub const BufSet = @import("buf_set.zig").BufSet;
-pub const Buffer = @import("buffer.zig").Buffer;
-pub const BufferOutStream = @import("io.zig").BufferOutStream;
-pub const DynLib = @import("dynamic_library.zig").DynLib;
-pub const HashMap = @import("hash_map.zig").HashMap;
-pub const LinkedList = @import("linked_list.zig").LinkedList;
-pub const Mutex = @import("mutex.zig").Mutex;
-pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
-pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
-pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
-pub const SpinLock = @import("spinlock.zig").SpinLock;
-
-pub const atomic = @import("atomic/index.zig");
-pub const base64 = @import("base64.zig");
-pub const build = @import("build.zig");
-pub const c = @import("c/index.zig");
-pub const coff = @import("coff.zig");
-pub const crypto = @import("crypto/index.zig");
-pub const cstr = @import("cstr.zig");
-pub const debug = @import("debug/index.zig");
-pub const dwarf = @import("dwarf.zig");
-pub const elf = @import("elf.zig");
-pub const empty_import = @import("empty.zig");
-pub const event = @import("event.zig");
-pub const fmt = @import("fmt/index.zig");
-pub const hash = @import("hash/index.zig");
-pub const hash_map = @import("hash_map.zig");
-pub const heap = @import("heap.zig");
-pub const io = @import("io.zig");
-pub const json = @import("json.zig");
-pub const lazyInit = @import("lazy_init.zig").lazyInit;
-pub const macho = @import("macho.zig");
-pub const math = @import("math/index.zig");
-pub const mem = @import("mem.zig");
-pub const meta = @import("meta/index.zig");
-pub const net = @import("net.zig");
-pub const os = @import("os/index.zig");
-pub const pdb = @import("pdb.zig");
-pub const rand = @import("rand/index.zig");
-pub const rb = @import("rb.zig");
-pub const sort = @import("sort.zig");
-pub const testing = @import("testing.zig");
-pub const unicode = @import("unicode.zig");
-pub const zig = @import("zig/index.zig");
-
-test "std" {
- // run tests from these
- _ = @import("array_list.zig");
- _ = @import("atomic/index.zig");
- _ = @import("buf_map.zig");
- _ = @import("buf_set.zig");
- _ = @import("buffer.zig");
- _ = @import("hash_map.zig");
- _ = @import("linked_list.zig");
- _ = @import("mutex.zig");
- _ = @import("statically_initialized_mutex.zig");
- _ = @import("segmented_list.zig");
- _ = @import("spinlock.zig");
-
- _ = @import("base64.zig");
- _ = @import("build.zig");
- _ = @import("c/index.zig");
- _ = @import("coff.zig");
- _ = @import("crypto/index.zig");
- _ = @import("cstr.zig");
- _ = @import("debug/index.zig");
- _ = @import("dwarf.zig");
- _ = @import("dynamic_library.zig");
- _ = @import("elf.zig");
- _ = @import("empty.zig");
- _ = @import("event.zig");
- _ = @import("fmt/index.zig");
- _ = @import("hash/index.zig");
- _ = @import("heap.zig");
- _ = @import("io.zig");
- _ = @import("json.zig");
- _ = @import("lazy_init.zig");
- _ = @import("macho.zig");
- _ = @import("math/index.zig");
- _ = @import("mem.zig");
- _ = @import("meta/index.zig");
- _ = @import("net.zig");
- _ = @import("os/index.zig");
- _ = @import("pdb.zig");
- _ = @import("priority_queue.zig");
- _ = @import("rand/index.zig");
- _ = @import("sort.zig");
- _ = @import("testing.zig");
- _ = @import("unicode.zig");
- _ = @import("zig/index.zig");
-}
diff --git a/std/io.zig b/std/io.zig
index f6e3790af6f6e777bbf52ca8667e2b31c401bfe3..7756f361169f0eb56a5c8fee341373556ad3ce44 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const c = std.c;
diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig
index a766f4fb8981a48a1a5819aaa8b026d25a6a7d4c..5529e42ff1d9565056e7315a48fc8c4d0d83a191 100644
--- a/std/io/seekable_stream.zig
+++ b/std/io/seekable_stream.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const InStream = std.io.InStream;
pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
diff --git a/std/io_test.zig b/std/io_test.zig
index c07ff137ab811b772940fb785b6b495bedf1deb8..58d542307cb12cd60d280ea80126a4520f44c6eb 100644
--- a/std/io_test.zig
+++ b/std/io_test.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const io = std.io;
const meta = std.meta;
const trait = std.trait;
diff --git a/std/json.zig b/std/json.zig
index dd053e7635eeec8f673769e791d84c9c1f2ba326..551c3a8da70ddee261bdea75e01b4bae979ffa82 100644
--- a/std/json.zig
+++ b/std/json.zig
@@ -2,7 +2,7 @@
//
// https://tools.ietf.org/html/rfc8259
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const testing = std.testing;
const mem = std.mem;
diff --git a/std/json_test.zig b/std/json_test.zig
index edc50be8cb3e3ef1b4a1639b7524f06fd57fa3d2..a323e6e9799183af36e897fb513c7bd0f1a83b2c 100644
--- a/std/json_test.zig
+++ b/std/json_test.zig
@@ -3,7 +3,7 @@
// Tests are taken from https://github.com/nst/JSONTestSuite
// Read also http://seriot.ch/parsing_json.php for a good overview.
-const std = @import("index.zig");
+const std = @import("std.zig");
fn ok(comptime s: []const u8) void {
std.testing.expect(std.json.validate(s));
diff --git a/std/lazy_init.zig b/std/lazy_init.zig
index a09168786ba0bc73cc9e31c24e6636bbb83ecc96..7beabb9cdeeb948c3fe6b4107009dfd091af4907 100644
--- a/std/lazy_init.zig
+++ b/std/lazy_init.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/linked_list.zig b/std/linked_list.zig
index 86e5cd056ef61503814464c5a6db4b04ae5ba211..c4ad525913f528cf02564ac3b58c1c28489b867a 100644
--- a/std/linked_list.zig
+++ b/std/linked_list.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
diff --git a/std/math.zig b/std/math.zig
new file mode 100644
index 0000000000000000000000000000000000000000..cead68577833b5d32c22000dd565c8aa0b5bb3d7
--- /dev/null
+++ b/std/math.zig
@@ -0,0 +1,797 @@
+const builtin = @import("builtin");
+const std = @import("std.zig");
+const TypeId = builtin.TypeId;
+const assert = std.debug.assert;
+const testing = std.testing;
+
+pub const e = 2.71828182845904523536028747135266249775724709369995;
+pub const pi = 3.14159265358979323846264338327950288419716939937510;
+
+// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
+pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001));
+pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000));
+pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
+pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000));
+pub const f128_toint = 1.0 / f128_epsilon;
+
+// float.h details
+pub const f64_true_min = 4.94065645841246544177e-324;
+pub const f64_min = 2.2250738585072014e-308;
+pub const f64_max = 1.79769313486231570815e+308;
+pub const f64_epsilon = 2.22044604925031308085e-16;
+pub const f64_toint = 1.0 / f64_epsilon;
+
+pub const f32_true_min = 1.40129846432481707092e-45;
+pub const f32_min = 1.17549435082228750797e-38;
+pub const f32_max = 3.40282346638528859812e+38;
+pub const f32_epsilon = 1.1920928955078125e-07;
+pub const f32_toint = 1.0 / f32_epsilon;
+
+pub const f16_true_min = 0.000000059604644775390625; // 2**-24
+pub const f16_min = 0.00006103515625; // 2**-14
+pub const f16_max = 65504;
+pub const f16_epsilon = 0.0009765625; // 2**-10
+pub const f16_toint = 1.0 / f16_epsilon;
+
+pub const nan_u16 = u16(0x7C01);
+pub const nan_f16 = @bitCast(f16, nan_u16);
+
+pub const inf_u16 = u16(0x7C00);
+pub const inf_f16 = @bitCast(f16, inf_u16);
+
+pub const nan_u32 = u32(0x7F800001);
+pub const nan_f32 = @bitCast(f32, nan_u32);
+
+pub const inf_u32 = u32(0x7F800000);
+pub const inf_f32 = @bitCast(f32, inf_u32);
+
+pub const nan_u64 = u64(0x7FF << 52) | 1;
+pub const nan_f64 = @bitCast(f64, nan_u64);
+
+pub const inf_u64 = u64(0x7FF << 52);
+pub const inf_f64 = @bitCast(f64, inf_u64);
+
+pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
+pub const nan_f128 = @bitCast(f128, nan_u128);
+
+pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
+pub const inf_f128 = @bitCast(f128, inf_u128);
+
+pub const nan = @import("math/nan.zig").nan;
+pub const snan = @import("math/nan.zig").snan;
+pub const inf = @import("math/inf.zig").inf;
+
+pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
+ assert(@typeId(T) == TypeId.Float);
+ return fabs(x - y) < epsilon;
+}
+
+// TODO: Hide the following in an internal module.
+pub fn forceEval(value: var) void {
+ const T = @typeOf(value);
+ switch (T) {
+ f16 => {
+ var x: f16 = undefined;
+ const p = @ptrCast(*volatile f16, &x);
+ p.* = x;
+ },
+ f32 => {
+ var x: f32 = undefined;
+ const p = @ptrCast(*volatile f32, &x);
+ p.* = x;
+ },
+ f64 => {
+ var x: f64 = undefined;
+ const p = @ptrCast(*volatile f64, &x);
+ p.* = x;
+ },
+ else => {
+ @compileError("forceEval not implemented for " ++ @typeName(T));
+ },
+ }
+}
+
+pub fn raiseInvalid() void {
+ // Raise INVALID fpu exception
+}
+
+pub fn raiseUnderflow() void {
+ // Raise UNDERFLOW fpu exception
+}
+
+pub fn raiseOverflow() void {
+ // Raise OVERFLOW fpu exception
+}
+
+pub fn raiseInexact() void {
+ // Raise INEXACT fpu exception
+}
+
+pub fn raiseDivByZero() void {
+ // Raise INEXACT fpu exception
+}
+
+pub const isNan = @import("math/isnan.zig").isNan;
+pub const isSignalNan = @import("math/isnan.zig").isSignalNan;
+pub const fabs = @import("math/fabs.zig").fabs;
+pub const ceil = @import("math/ceil.zig").ceil;
+pub const floor = @import("math/floor.zig").floor;
+pub const trunc = @import("math/trunc.zig").trunc;
+pub const round = @import("math/round.zig").round;
+pub const frexp = @import("math/frexp.zig").frexp;
+pub const frexp32_result = @import("math/frexp.zig").frexp32_result;
+pub const frexp64_result = @import("math/frexp.zig").frexp64_result;
+pub const modf = @import("math/modf.zig").modf;
+pub const modf32_result = @import("math/modf.zig").modf32_result;
+pub const modf64_result = @import("math/modf.zig").modf64_result;
+pub const copysign = @import("math/copysign.zig").copysign;
+pub const isFinite = @import("math/isfinite.zig").isFinite;
+pub const isInf = @import("math/isinf.zig").isInf;
+pub const isPositiveInf = @import("math/isinf.zig").isPositiveInf;
+pub const isNegativeInf = @import("math/isinf.zig").isNegativeInf;
+pub const isNormal = @import("math/isnormal.zig").isNormal;
+pub const signbit = @import("math/signbit.zig").signbit;
+pub const scalbn = @import("math/scalbn.zig").scalbn;
+pub const pow = @import("math/pow.zig").pow;
+pub const powi = @import("math/powi.zig").powi;
+pub const sqrt = @import("math/sqrt.zig").sqrt;
+pub const cbrt = @import("math/cbrt.zig").cbrt;
+pub const acos = @import("math/acos.zig").acos;
+pub const asin = @import("math/asin.zig").asin;
+pub const atan = @import("math/atan.zig").atan;
+pub const atan2 = @import("math/atan2.zig").atan2;
+pub const hypot = @import("math/hypot.zig").hypot;
+pub const exp = @import("math/exp.zig").exp;
+pub const exp2 = @import("math/exp2.zig").exp2;
+pub const expm1 = @import("math/expm1.zig").expm1;
+pub const ilogb = @import("math/ilogb.zig").ilogb;
+pub const ln = @import("math/ln.zig").ln;
+pub const log = @import("math/log.zig").log;
+pub const log2 = @import("math/log2.zig").log2;
+pub const log10 = @import("math/log10.zig").log10;
+pub const log1p = @import("math/log1p.zig").log1p;
+pub const fma = @import("math/fma.zig").fma;
+pub const asinh = @import("math/asinh.zig").asinh;
+pub const acosh = @import("math/acosh.zig").acosh;
+pub const atanh = @import("math/atanh.zig").atanh;
+pub const sinh = @import("math/sinh.zig").sinh;
+pub const cosh = @import("math/cosh.zig").cosh;
+pub const tanh = @import("math/tanh.zig").tanh;
+pub const cos = @import("math/cos.zig").cos;
+pub const sin = @import("math/sin.zig").sin;
+pub const tan = @import("math/tan.zig").tan;
+
+pub const complex = @import("math/complex.zig");
+pub const Complex = complex.Complex;
+
+pub const big = @import("math/big.zig");
+
+test "math" {
+ _ = @import("math/nan.zig");
+ _ = @import("math/isnan.zig");
+ _ = @import("math/fabs.zig");
+ _ = @import("math/ceil.zig");
+ _ = @import("math/floor.zig");
+ _ = @import("math/trunc.zig");
+ _ = @import("math/round.zig");
+ _ = @import("math/frexp.zig");
+ _ = @import("math/modf.zig");
+ _ = @import("math/copysign.zig");
+ _ = @import("math/isfinite.zig");
+ _ = @import("math/isinf.zig");
+ _ = @import("math/isnormal.zig");
+ _ = @import("math/signbit.zig");
+ _ = @import("math/scalbn.zig");
+ _ = @import("math/pow.zig");
+ _ = @import("math/powi.zig");
+ _ = @import("math/sqrt.zig");
+ _ = @import("math/cbrt.zig");
+ _ = @import("math/acos.zig");
+ _ = @import("math/asin.zig");
+ _ = @import("math/atan.zig");
+ _ = @import("math/atan2.zig");
+ _ = @import("math/hypot.zig");
+ _ = @import("math/exp.zig");
+ _ = @import("math/exp2.zig");
+ _ = @import("math/expm1.zig");
+ _ = @import("math/ilogb.zig");
+ _ = @import("math/ln.zig");
+ _ = @import("math/log.zig");
+ _ = @import("math/log2.zig");
+ _ = @import("math/log10.zig");
+ _ = @import("math/log1p.zig");
+ _ = @import("math/fma.zig");
+ _ = @import("math/asinh.zig");
+ _ = @import("math/acosh.zig");
+ _ = @import("math/atanh.zig");
+ _ = @import("math/sinh.zig");
+ _ = @import("math/cosh.zig");
+ _ = @import("math/tanh.zig");
+ _ = @import("math/sin.zig");
+ _ = @import("math/cos.zig");
+ _ = @import("math/tan.zig");
+
+ _ = @import("math/complex.zig");
+
+ _ = @import("math/big.zig");
+}
+
+pub fn floatMantissaBits(comptime T: type) comptime_int {
+ assert(@typeId(T) == builtin.TypeId.Float);
+
+ return switch (T.bit_count) {
+ 16 => 10,
+ 32 => 23,
+ 64 => 52,
+ 80 => 64,
+ 128 => 112,
+ else => @compileError("unknown floating point type " ++ @typeName(T)),
+ };
+}
+
+pub fn floatExponentBits(comptime T: type) comptime_int {
+ assert(@typeId(T) == builtin.TypeId.Float);
+
+ return switch (T.bit_count) {
+ 16 => 5,
+ 32 => 8,
+ 64 => 11,
+ 80 => 15,
+ 128 => 15,
+ else => @compileError("unknown floating point type " ++ @typeName(T)),
+ };
+}
+
+pub fn min(x: var, y: var) @typeOf(x + y) {
+ return if (x < y) x else y;
+}
+
+test "math.min" {
+ testing.expect(min(i32(-1), i32(2)) == -1);
+}
+
+pub fn max(x: var, y: var) @typeOf(x + y) {
+ return if (x > y) x else y;
+}
+
+test "math.max" {
+ testing.expect(max(i32(-1), i32(2)) == 2);
+}
+
+pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
+ var answer: T = undefined;
+ return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
+ var answer: T = undefined;
+ return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
+ var answer: T = undefined;
+ return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+pub fn negate(x: var) !@typeOf(x) {
+ return sub(@typeOf(x), 0, x);
+}
+
+pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
+ var answer: T = undefined;
+ return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
+}
+
+/// Shifts left. Overflowed bits are truncated.
+/// A negative shift amount results in a right shift.
+pub fn shl(comptime T: type, a: T, shift_amt: var) T {
+ const abs_shift_amt = absCast(shift_amt);
+ const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
+
+ if (@typeOf(shift_amt).is_signed) {
+ if (shift_amt >= 0) {
+ return a << casted_shift_amt;
+ } else {
+ return a >> casted_shift_amt;
+ }
+ }
+
+ return a << casted_shift_amt;
+}
+
+test "math.shl" {
+ testing.expect(shl(u8, 0b11111111, usize(3)) == 0b11111000);
+ testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
+ testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
+ testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
+}
+
+/// Shifts right. Overflowed bits are truncated.
+/// A negative shift amount results in a lefft shift.
+pub fn shr(comptime T: type, a: T, shift_amt: var) T {
+ const abs_shift_amt = absCast(shift_amt);
+ const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
+
+ if (@typeOf(shift_amt).is_signed) {
+ if (shift_amt >= 0) {
+ return a >> casted_shift_amt;
+ } else {
+ return a << casted_shift_amt;
+ }
+ }
+
+ return a >> casted_shift_amt;
+}
+
+test "math.shr" {
+ testing.expect(shr(u8, 0b11111111, usize(3)) == 0b00011111);
+ testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
+ testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
+ testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
+}
+
+/// Rotates right. Only unsigned values can be rotated.
+/// Negative shift values results in shift modulo the bit count.
+pub fn rotr(comptime T: type, x: T, r: var) T {
+ if (T.is_signed) {
+ @compileError("cannot rotate signed integer");
+ } else {
+ const ar = @mod(r, T.bit_count);
+ return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
+ }
+}
+
+test "math.rotr" {
+ testing.expect(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
+ testing.expect(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
+ testing.expect(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
+ testing.expect(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
+ testing.expect(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
+}
+
+/// Rotates left. Only unsigned values can be rotated.
+/// Negative shift values results in shift modulo the bit count.
+pub fn rotl(comptime T: type, x: T, r: var) T {
+ if (T.is_signed) {
+ @compileError("cannot rotate signed integer");
+ } else {
+ const ar = @mod(r, T.bit_count);
+ return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
+ }
+}
+
+test "math.rotl" {
+ testing.expect(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
+ testing.expect(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
+ testing.expect(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
+ testing.expect(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
+ testing.expect(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
+}
+
+pub fn Log2Int(comptime T: type) type {
+ // comptime ceil log2
+ comptime var count = 0;
+ comptime var s = T.bit_count - 1;
+ inline while (s != 0) : (s >>= 1) {
+ count += 1;
+ }
+
+ return @IntType(false, count);
+}
+
+pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
+ assert(from <= to);
+ if (from == 0 and to == 0) {
+ return u0;
+ }
+ const is_signed = from < 0;
+ const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
+ const base = log2(largest_positive_integer);
+ const upper = (1 << base) - 1;
+ var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
+ if (is_signed) {
+ magnitude_bits += 1;
+ }
+ return @IntType(is_signed, magnitude_bits);
+}
+
+test "math.IntFittingRange" {
+ testing.expect(IntFittingRange(0, 0) == u0);
+ testing.expect(IntFittingRange(0, 1) == u1);
+ testing.expect(IntFittingRange(0, 2) == u2);
+ testing.expect(IntFittingRange(0, 3) == u2);
+ testing.expect(IntFittingRange(0, 4) == u3);
+ testing.expect(IntFittingRange(0, 7) == u3);
+ testing.expect(IntFittingRange(0, 8) == u4);
+ testing.expect(IntFittingRange(0, 9) == u4);
+ testing.expect(IntFittingRange(0, 15) == u4);
+ testing.expect(IntFittingRange(0, 16) == u5);
+ testing.expect(IntFittingRange(0, 17) == u5);
+ testing.expect(IntFittingRange(0, 4095) == u12);
+ testing.expect(IntFittingRange(2000, 4095) == u12);
+ testing.expect(IntFittingRange(0, 4096) == u13);
+ testing.expect(IntFittingRange(2000, 4096) == u13);
+ testing.expect(IntFittingRange(0, 4097) == u13);
+ testing.expect(IntFittingRange(2000, 4097) == u13);
+ testing.expect(IntFittingRange(0, 123456789123456798123456789) == u87);
+ testing.expect(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
+
+ testing.expect(IntFittingRange(-1, -1) == i1);
+ testing.expect(IntFittingRange(-1, 0) == i1);
+ testing.expect(IntFittingRange(-1, 1) == i2);
+ testing.expect(IntFittingRange(-2, -2) == i2);
+ testing.expect(IntFittingRange(-2, -1) == i2);
+ testing.expect(IntFittingRange(-2, 0) == i2);
+ testing.expect(IntFittingRange(-2, 1) == i2);
+ testing.expect(IntFittingRange(-2, 2) == i3);
+ testing.expect(IntFittingRange(-1, 2) == i3);
+ testing.expect(IntFittingRange(-1, 3) == i3);
+ testing.expect(IntFittingRange(-1, 4) == i4);
+ testing.expect(IntFittingRange(-1, 7) == i4);
+ testing.expect(IntFittingRange(-1, 8) == i5);
+ testing.expect(IntFittingRange(-1, 9) == i5);
+ testing.expect(IntFittingRange(-1, 15) == i5);
+ testing.expect(IntFittingRange(-1, 16) == i6);
+ testing.expect(IntFittingRange(-1, 17) == i6);
+ testing.expect(IntFittingRange(-1, 4095) == i13);
+ testing.expect(IntFittingRange(-4096, 4095) == i13);
+ testing.expect(IntFittingRange(-1, 4096) == i14);
+ testing.expect(IntFittingRange(-4097, 4095) == i14);
+ testing.expect(IntFittingRange(-1, 4097) == i14);
+ testing.expect(IntFittingRange(-1, 123456789123456798123456789) == i88);
+ testing.expect(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
+}
+
+test "math overflow functions" {
+ testOverflow();
+ comptime testOverflow();
+}
+
+fn testOverflow() void {
+ testing.expect((mul(i32, 3, 4) catch unreachable) == 12);
+ testing.expect((add(i32, 3, 4) catch unreachable) == 7);
+ testing.expect((sub(i32, 3, 4) catch unreachable) == -1);
+ testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
+}
+
+pub fn absInt(x: var) !@typeOf(x) {
+ const T = @typeOf(x);
+ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
+ comptime assert(T.is_signed); // must pass a signed integer to absInt
+
+ if (x == minInt(@typeOf(x))) {
+ return error.Overflow;
+ } else {
+ @setRuntimeSafety(false);
+ return if (x < 0) -x else x;
+ }
+}
+
+test "math.absInt" {
+ testAbsInt();
+ comptime testAbsInt();
+}
+fn testAbsInt() void {
+ testing.expect((absInt(i32(-10)) catch unreachable) == 10);
+ testing.expect((absInt(i32(10)) catch unreachable) == 10);
+}
+
+pub const absFloat = @import("fabs.zig").fabs;
+
+pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
+ @setRuntimeSafety(false);
+ if (denominator == 0) return error.DivisionByZero;
+ if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
+ return @divTrunc(numerator, denominator);
+}
+
+test "math.divTrunc" {
+ testDivTrunc();
+ comptime testDivTrunc();
+}
+fn testDivTrunc() void {
+ testing.expect((divTrunc(i32, 5, 3) catch unreachable) == 1);
+ testing.expect((divTrunc(i32, -5, 3) catch unreachable) == -1);
+ testing.expectError(error.DivisionByZero, divTrunc(i8, -5, 0));
+ testing.expectError(error.Overflow, divTrunc(i8, -128, -1));
+
+ testing.expect((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0);
+ testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
+}
+
+pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
+ @setRuntimeSafety(false);
+ if (denominator == 0) return error.DivisionByZero;
+ if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
+ return @divFloor(numerator, denominator);
+}
+
+test "math.divFloor" {
+ testDivFloor();
+ comptime testDivFloor();
+}
+fn testDivFloor() void {
+ testing.expect((divFloor(i32, 5, 3) catch unreachable) == 1);
+ testing.expect((divFloor(i32, -5, 3) catch unreachable) == -2);
+ testing.expectError(error.DivisionByZero, divFloor(i8, -5, 0));
+ testing.expectError(error.Overflow, divFloor(i8, -128, -1));
+
+ testing.expect((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0);
+ testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
+}
+
+pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
+ @setRuntimeSafety(false);
+ if (denominator == 0) return error.DivisionByZero;
+ if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
+ const result = @divTrunc(numerator, denominator);
+ if (result * denominator != numerator) return error.UnexpectedRemainder;
+ return result;
+}
+
+test "math.divExact" {
+ testDivExact();
+ comptime testDivExact();
+}
+fn testDivExact() void {
+ testing.expect((divExact(i32, 10, 5) catch unreachable) == 2);
+ testing.expect((divExact(i32, -10, 5) catch unreachable) == -2);
+ testing.expectError(error.DivisionByZero, divExact(i8, -5, 0));
+ testing.expectError(error.Overflow, divExact(i8, -128, -1));
+ testing.expectError(error.UnexpectedRemainder, divExact(i32, 5, 2));
+
+ testing.expect((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0);
+ testing.expect((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0);
+ testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0));
+}
+
+pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
+ @setRuntimeSafety(false);
+ if (denominator == 0) return error.DivisionByZero;
+ if (denominator < 0) return error.NegativeDenominator;
+ return @mod(numerator, denominator);
+}
+
+test "math.mod" {
+ testMod();
+ comptime testMod();
+}
+fn testMod() void {
+ testing.expect((mod(i32, -5, 3) catch unreachable) == 1);
+ testing.expect((mod(i32, 5, 3) catch unreachable) == 2);
+ testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));
+ testing.expectError(error.DivisionByZero, mod(i32, 10, 0));
+
+ testing.expect((mod(f32, -5, 3) catch unreachable) == 1);
+ testing.expect((mod(f32, 5, 3) catch unreachable) == 2);
+ testing.expectError(error.NegativeDenominator, mod(f32, 10, -1));
+ testing.expectError(error.DivisionByZero, mod(f32, 10, 0));
+}
+
+pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
+ @setRuntimeSafety(false);
+ if (denominator == 0) return error.DivisionByZero;
+ if (denominator < 0) return error.NegativeDenominator;
+ return @rem(numerator, denominator);
+}
+
+test "math.rem" {
+ testRem();
+ comptime testRem();
+}
+fn testRem() void {
+ testing.expect((rem(i32, -5, 3) catch unreachable) == -2);
+ testing.expect((rem(i32, 5, 3) catch unreachable) == 2);
+ testing.expectError(error.NegativeDenominator, rem(i32, 10, -1));
+ testing.expectError(error.DivisionByZero, rem(i32, 10, 0));
+
+ testing.expect((rem(f32, -5, 3) catch unreachable) == -2);
+ testing.expect((rem(f32, 5, 3) catch unreachable) == 2);
+ testing.expectError(error.NegativeDenominator, rem(f32, 10, -1));
+ testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
+}
+
+/// Returns the absolute value of the integer parameter.
+/// Result is an unsigned integer.
+pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
+ const uint = @IntType(false, @typeOf(x).bit_count);
+ if (x >= 0) return @intCast(uint, x);
+
+ return @intCast(uint, -(x + 1)) + 1;
+}
+
+test "math.absCast" {
+ testing.expect(absCast(i32(-999)) == 999);
+ testing.expect(@typeOf(absCast(i32(-999))) == u32);
+
+ testing.expect(absCast(i32(999)) == 999);
+ testing.expect(@typeOf(absCast(i32(999))) == u32);
+
+ testing.expect(absCast(i32(minInt(i32))) == -minInt(i32));
+ testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32);
+}
+
+/// Returns the negation of the integer parameter.
+/// Result is a signed integer.
+pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
+ if (@typeOf(x).is_signed) return negate(x);
+
+ const int = @IntType(true, @typeOf(x).bit_count);
+ if (x > -minInt(int)) return error.Overflow;
+
+ if (x == -minInt(int)) return minInt(int);
+
+ return -@intCast(int, x);
+}
+
+test "math.negateCast" {
+ testing.expect((negateCast(u32(999)) catch unreachable) == -999);
+ testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32);
+
+ testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32));
+ testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32);
+
+ testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10)));
+}
+
+/// Cast an integer to a different integer type. If the value doesn't fit,
+/// return an error.
+pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
+ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
+ comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer
+ if (maxInt(@typeOf(x)) > maxInt(T) and x > maxInt(T)) {
+ return error.Overflow;
+ } else if (minInt(@typeOf(x)) < minInt(T) and x < minInt(T)) {
+ return error.Overflow;
+ } else {
+ return @intCast(T, x);
+ }
+}
+
+test "math.cast" {
+ testing.expectError(error.Overflow, cast(u8, u32(300)));
+ testing.expectError(error.Overflow, cast(i8, i32(-200)));
+ testing.expectError(error.Overflow, cast(u8, i8(-1)));
+ testing.expectError(error.Overflow, cast(u64, i8(-1)));
+
+ testing.expect((try cast(u8, u32(255))) == u8(255));
+ testing.expect(@typeOf(try cast(u8, u32(255))) == u8);
+}
+
+pub const AlignCastError = error{UnalignedMemory};
+
+/// Align cast a pointer but return an error if it's the wrong alignment
+pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alignCast(alignment, ptr)) {
+ const addr = @ptrToInt(ptr);
+ if (addr % alignment != 0) {
+ return error.UnalignedMemory;
+ }
+ return @alignCast(alignment, ptr);
+}
+
+pub fn floorPowerOfTwo(comptime T: type, value: T) T {
+ var x = value;
+
+ comptime var i = 1;
+ inline while (T.bit_count > i) : (i *= 2) {
+ x |= (x >> i);
+ }
+
+ return x - (x >> 1);
+}
+
+test "math.floorPowerOfTwo" {
+ testFloorPowerOfTwo();
+ comptime testFloorPowerOfTwo();
+}
+
+pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
+ assert(x != 0);
+ return @intCast(Log2Int(T), T.bit_count - 1 - @clz(x));
+}
+
+pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
+ assert(x != 0);
+ const log2_val = log2_int(T, x);
+ if (T(1) << log2_val == x)
+ return log2_val;
+ return log2_val + 1;
+}
+
+test "std.math.log2_int_ceil" {
+ testing.expect(log2_int_ceil(u32, 1) == 0);
+ testing.expect(log2_int_ceil(u32, 2) == 1);
+ testing.expect(log2_int_ceil(u32, 3) == 2);
+ testing.expect(log2_int_ceil(u32, 4) == 2);
+ testing.expect(log2_int_ceil(u32, 5) == 3);
+ testing.expect(log2_int_ceil(u32, 6) == 3);
+ testing.expect(log2_int_ceil(u32, 7) == 3);
+ testing.expect(log2_int_ceil(u32, 8) == 3);
+ testing.expect(log2_int_ceil(u32, 9) == 4);
+ testing.expect(log2_int_ceil(u32, 10) == 4);
+}
+
+fn testFloorPowerOfTwo() void {
+ testing.expect(floorPowerOfTwo(u32, 63) == 32);
+ testing.expect(floorPowerOfTwo(u32, 64) == 64);
+ testing.expect(floorPowerOfTwo(u32, 65) == 64);
+ testing.expect(floorPowerOfTwo(u4, 7) == 4);
+ testing.expect(floorPowerOfTwo(u4, 8) == 8);
+ testing.expect(floorPowerOfTwo(u4, 9) == 8);
+}
+
+pub fn lossyCast(comptime T: type, value: var) T {
+ switch (@typeInfo(@typeOf(value))) {
+ builtin.TypeId.Int => return @intToFloat(T, value),
+ builtin.TypeId.Float => return @floatCast(T, value),
+ builtin.TypeId.ComptimeInt => return T(value),
+ builtin.TypeId.ComptimeFloat => return T(value),
+ else => @compileError("bad type"),
+ }
+}
+
+test "math.f64_min" {
+ const f64_min_u64 = 0x0010000000000000;
+ const fmin: f64 = f64_min;
+ testing.expect(@bitCast(u64, fmin) == f64_min_u64);
+}
+
+pub fn maxInt(comptime T: type) comptime_int {
+ const info = @typeInfo(T);
+ const bit_count = info.Int.bits;
+ if (bit_count == 0) return 0;
+ return (1 << (bit_count - @boolToInt(info.Int.is_signed))) - 1;
+}
+
+pub fn minInt(comptime T: type) comptime_int {
+ const info = @typeInfo(T);
+ const bit_count = info.Int.bits;
+ if (!info.Int.is_signed) return 0;
+ if (bit_count == 0) return 0;
+ return -(1 << (bit_count - 1));
+}
+
+test "minInt and maxInt" {
+ testing.expect(maxInt(u0) == 0);
+ testing.expect(maxInt(u1) == 1);
+ testing.expect(maxInt(u8) == 255);
+ testing.expect(maxInt(u16) == 65535);
+ testing.expect(maxInt(u32) == 4294967295);
+ testing.expect(maxInt(u64) == 18446744073709551615);
+ testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
+
+ testing.expect(maxInt(i0) == 0);
+ testing.expect(maxInt(i1) == 0);
+ testing.expect(maxInt(i8) == 127);
+ testing.expect(maxInt(i16) == 32767);
+ testing.expect(maxInt(i32) == 2147483647);
+ testing.expect(maxInt(i63) == 4611686018427387903);
+ testing.expect(maxInt(i64) == 9223372036854775807);
+ testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
+
+ testing.expect(minInt(u0) == 0);
+ testing.expect(minInt(u1) == 0);
+ testing.expect(minInt(u8) == 0);
+ testing.expect(minInt(u16) == 0);
+ testing.expect(minInt(u32) == 0);
+ testing.expect(minInt(u63) == 0);
+ testing.expect(minInt(u64) == 0);
+ testing.expect(minInt(u128) == 0);
+
+ testing.expect(minInt(i0) == 0);
+ testing.expect(minInt(i1) == -1);
+ testing.expect(minInt(i8) == -128);
+ testing.expect(minInt(i16) == -32768);
+ testing.expect(minInt(i32) == -2147483648);
+ testing.expect(minInt(i63) == -4611686018427387904);
+ testing.expect(minInt(i64) == -9223372036854775808);
+ testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
+}
+
+test "max value type" {
+ // If the type of maxInt(i32) was i32 then this implicit cast to
+ // u32 would not work. But since the value is a number literal,
+ // it works fine.
+ const x: u32 = maxInt(i32);
+ testing.expect(x == 2147483647);
+}
diff --git a/std/math/acos.zig b/std/math/acos.zig
index 734f7a8651679d7503e23f615588cf53ebab7633..763d9d8abde256bf4fe361cc305e519905aca952 100644
--- a/std/math/acos.zig
+++ b/std/math/acos.zig
@@ -2,7 +2,7 @@
//
// - acos(x) = nan if x < -1 or x > 1
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/acosh.zig b/std/math/acosh.zig
index a9c4a908ef15aaf72ffab1c852e34218f97c18d4..a2a99268635d6972e279f85b883d8de5e812f137 100644
--- a/std/math/acosh.zig
+++ b/std/math/acosh.zig
@@ -4,7 +4,7 @@
// - acosh(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/asin.zig b/std/math/asin.zig
index c9dbdf704f0b051f64723855ca0aa7f1c2deb0d3..b01a1ac49ea067aae9154df67a2bd9a9a656fe98 100644
--- a/std/math/asin.zig
+++ b/std/math/asin.zig
@@ -3,7 +3,7 @@
// - asin(+-0) = +-0
// - asin(x) = nan if x < -1 or x > 1
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/asinh.zig b/std/math/asinh.zig
index 05bd8d008ec9c3e63665c06202c2f4e2c8f28660..cef9bfb23f520cdcbcedccbdfe22bc26168bfed4 100644
--- a/std/math/asinh.zig
+++ b/std/math/asinh.zig
@@ -4,7 +4,7 @@
// - asinh(+-inf) = +-inf
// - asinh(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/atan.zig b/std/math/atan.zig
index 72d17b4db2b25825dbedf64280b352dbf7249c41..ba5a11dd10dc794a4164f686135084c703fd778a 100644
--- a/std/math/atan.zig
+++ b/std/math/atan.zig
@@ -3,7 +3,7 @@
// - atan(+-0) = +-0
// - atan(+-inf) = +-pi/2
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/atan2.zig b/std/math/atan2.zig
index 6e1f67cfbba5642c51184a4668e5eade684211bc..7f135074021197bd6a00848320bc8b5d2536394d 100644
--- a/std/math/atan2.zig
+++ b/std/math/atan2.zig
@@ -18,7 +18,7 @@
// atan2(+inf, x) = +pi/2
// atan2(-inf, x) = -pi/2
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/atanh.zig b/std/math/atanh.zig
index f2feab02070e3df5cf4ce95bbc5440a2066386ce..9056064f5a48c8cc23479b4db159aafe8450b46e 100644
--- a/std/math/atanh.zig
+++ b/std/math/atanh.zig
@@ -4,7 +4,7 @@
// - atanh(x) = nan if |x| > 1 with signal
// - atanh(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/big.zig b/std/math/big.zig
new file mode 100644
index 0000000000000000000000000000000000000000..94b6d864e783827d5fc250b956974003a147382b
--- /dev/null
+++ b/std/math/big.zig
@@ -0,0 +1,5 @@
+pub use @import("big/int.zig");
+
+test "math.big" {
+ _ = @import("big/int.zig");
+}
diff --git a/std/math/big/index.zig b/std/math/big/index.zig
deleted file mode 100644
index 26fa538c4f0418c8e727686a6f2be2bccb35d14a..0000000000000000000000000000000000000000
--- a/std/math/big/index.zig
+++ /dev/null
@@ -1,5 +0,0 @@
-pub use @import("int.zig");
-
-test "math.big" {
- _ = @import("int.zig");
-}
diff --git a/std/math/big/int.zig b/std/math/big/int.zig
index f21e5df8aa4f0aa37f2c1bcf057b65caf6e5992d..7fca4a147fc478a610b1c5c3f50a4e764085b5e0 100644
--- a/std/math/big/int.zig
+++ b/std/math/big/int.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const builtin = @import("builtin");
const debug = std.debug;
const testing = std.testing;
diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig
index 957e026af45e65267728ae6e566bd2453502849d..94972552697a80858f1be15218995b1002dfbb99 100644
--- a/std/math/cbrt.zig
+++ b/std/math/cbrt.zig
@@ -4,7 +4,7 @@
// - cbrt(+-inf) = +-inf
// - cbrt(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/ceil.zig b/std/math/ceil.zig
index 5c6b98b2ca96f18d84b7bc54a009da59fcc79c9d..da83e0ec59ed737bfb4bb41e91e6a77055c66ac5 100644
--- a/std/math/ceil.zig
+++ b/std/math/ceil.zig
@@ -5,7 +5,7 @@
// - ceil(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/complex.zig b/std/math/complex.zig
new file mode 100644
index 0000000000000000000000000000000000000000..cc0573b2271f7850a9dcaead084c329556050b28
--- /dev/null
+++ b/std/math/complex.zig
@@ -0,0 +1,171 @@
+const std = @import("../std.zig");
+const testing = std.testing;
+const math = std.math;
+
+pub const abs = @import("complex/abs.zig").abs;
+pub const acosh = @import("complex/acosh.zig").acosh;
+pub const acos = @import("complex/acos.zig").acos;
+pub const arg = @import("complex/arg.zig").arg;
+pub const asinh = @import("complex/asinh.zig").asinh;
+pub const asin = @import("complex/asin.zig").asin;
+pub const atanh = @import("complex/atanh.zig").atanh;
+pub const atan = @import("complex/atan.zig").atan;
+pub const conj = @import("complex/conj.zig").conj;
+pub const cosh = @import("complex/cosh.zig").cosh;
+pub const cos = @import("complex/cos.zig").cos;
+pub const exp = @import("complex/exp.zig").exp;
+pub const log = @import("complex/log.zig").log;
+pub const pow = @import("complex/pow.zig").pow;
+pub const proj = @import("complex/proj.zig").proj;
+pub const sinh = @import("complex/sinh.zig").sinh;
+pub const sin = @import("complex/sin.zig").sin;
+pub const sqrt = @import("complex/sqrt.zig").sqrt;
+pub const tanh = @import("complex/tanh.zig").tanh;
+pub const tan = @import("complex/tan.zig").tan;
+
+pub fn Complex(comptime T: type) type {
+ return struct {
+ const Self = @This();
+
+ re: T,
+ im: T,
+
+ pub fn new(re: T, im: T) Self {
+ return Self{
+ .re = re,
+ .im = im,
+ };
+ }
+
+ pub fn add(self: Self, other: Self) Self {
+ return Self{
+ .re = self.re + other.re,
+ .im = self.im + other.im,
+ };
+ }
+
+ pub fn sub(self: Self, other: Self) Self {
+ return Self{
+ .re = self.re - other.re,
+ .im = self.im - other.im,
+ };
+ }
+
+ pub fn mul(self: Self, other: Self) Self {
+ return Self{
+ .re = self.re * other.re - self.im * other.im,
+ .im = self.im * other.re + self.re * other.im,
+ };
+ }
+
+ pub fn div(self: Self, other: Self) Self {
+ const re_num = self.re * other.re + self.im * other.im;
+ const im_num = self.im * other.re - self.re * other.im;
+ const den = other.re * other.re + other.im * other.im;
+
+ return Self{
+ .re = re_num / den,
+ .im = im_num / den,
+ };
+ }
+
+ pub fn conjugate(self: Self) Self {
+ return Self{
+ .re = self.re,
+ .im = -self.im,
+ };
+ }
+
+ pub fn reciprocal(self: Self) Self {
+ const m = self.re * self.re + self.im * self.im;
+ return Self{
+ .re = self.re / m,
+ .im = -self.im / m,
+ };
+ }
+
+ pub fn magnitude(self: Self) T {
+ return math.sqrt(self.re * self.re + self.im * self.im);
+ }
+ };
+}
+
+const epsilon = 0.0001;
+
+test "complex.add" {
+ const a = Complex(f32).new(5, 3);
+ const b = Complex(f32).new(2, 7);
+ const c = a.add(b);
+
+ testing.expect(c.re == 7 and c.im == 10);
+}
+
+test "complex.sub" {
+ const a = Complex(f32).new(5, 3);
+ const b = Complex(f32).new(2, 7);
+ const c = a.sub(b);
+
+ testing.expect(c.re == 3 and c.im == -4);
+}
+
+test "complex.mul" {
+ const a = Complex(f32).new(5, 3);
+ const b = Complex(f32).new(2, 7);
+ const c = a.mul(b);
+
+ testing.expect(c.re == -11 and c.im == 41);
+}
+
+test "complex.div" {
+ const a = Complex(f32).new(5, 3);
+ const b = Complex(f32).new(2, 7);
+ const c = a.div(b);
+
+ testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
+ math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
+}
+
+test "complex.conjugate" {
+ const a = Complex(f32).new(5, 3);
+ const c = a.conjugate();
+
+ testing.expect(c.re == 5 and c.im == -3);
+}
+
+test "complex.reciprocal" {
+ const a = Complex(f32).new(5, 3);
+ const c = a.reciprocal();
+
+ testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
+ math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
+}
+
+test "complex.magnitude" {
+ const a = Complex(f32).new(5, 3);
+ const c = a.magnitude();
+
+ testing.expect(math.approxEq(f32, c, 5.83095, epsilon));
+}
+
+test "complex.cmath" {
+ _ = @import("complex/abs.zig");
+ _ = @import("complex/acosh.zig");
+ _ = @import("complex/acos.zig");
+ _ = @import("complex/arg.zig");
+ _ = @import("complex/asinh.zig");
+ _ = @import("complex/asin.zig");
+ _ = @import("complex/atanh.zig");
+ _ = @import("complex/atan.zig");
+ _ = @import("complex/conj.zig");
+ _ = @import("complex/cosh.zig");
+ _ = @import("complex/cos.zig");
+ _ = @import("complex/exp.zig");
+ _ = @import("complex/log.zig");
+ _ = @import("complex/pow.zig");
+ _ = @import("complex/proj.zig");
+ _ = @import("complex/sinh.zig");
+ _ = @import("complex/sin.zig");
+ _ = @import("complex/sqrt.zig");
+ _ = @import("complex/tanh.zig");
+ _ = @import("complex/tan.zig");
+}
diff --git a/std/math/complex/abs.zig b/std/math/complex/abs.zig
index 245d67d4c57fa8684cfae99b5274f5ff8a68da5c..e1368d6ef64414793d4639fe5d8bfff9fab30e98 100644
--- a/std/math/complex/abs.zig
+++ b/std/math/complex/abs.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/acos.zig b/std/math/complex/acos.zig
index 1b314bc31a80e76c1d8af410ed32b59693405dcd..8aed26a71b5e3ed3be3d42cab1679ce60ee2d750 100644
--- a/std/math/complex/acos.zig
+++ b/std/math/complex/acos.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/acosh.zig b/std/math/complex/acosh.zig
index 0e4c0121f4dc13867a0a644f18b838043905161e..e72bf431fe528a3f89fe1c6abbf8824de32e798f 100644
--- a/std/math/complex/acosh.zig
+++ b/std/math/complex/acosh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/arg.zig b/std/math/complex/arg.zig
index be117a59401b685d92f024b6bae8fc8fca640a62..0a2441d1fdf3c7382699d9aa2ccb8535828f4fb6 100644
--- a/std/math/complex/arg.zig
+++ b/std/math/complex/arg.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/asin.zig b/std/math/complex/asin.zig
index cf802ea206418a66c2dac3992340612b860c0686..6be775d7484c997849a0dead3b2892df9f4bde81 100644
--- a/std/math/complex/asin.zig
+++ b/std/math/complex/asin.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/asinh.zig b/std/math/complex/asinh.zig
index 0386a636b0e50bb245aa62fc3e83974c861b07ad..8e0903675070c8660e859ce88804f609c612f2c3 100644
--- a/std/math/complex/asinh.zig
+++ b/std/math/complex/asinh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/atan.zig b/std/math/complex/atan.zig
index 8e60e58e43faca85af9d85657a3e63cc9a658c2e..6b83adbd9761d392e993aa31cc201468ede8a2b1 100644
--- a/std/math/complex/atan.zig
+++ b/std/math/complex/atan.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/atanh.zig b/std/math/complex/atanh.zig
index 5b18fe1992f7d92da57a787f412eefac1f996346..8edfb6e78e758d86ed49caaaba2fbe02035f5f61 100644
--- a/std/math/complex/atanh.zig
+++ b/std/math/complex/atanh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/conj.zig b/std/math/complex/conj.zig
index 143543f9e7e81058f08c4f0dd573319eb9761a88..7a42d365eaf8b8b5b960134bf33c3e1d738be868 100644
--- a/std/math/complex/conj.zig
+++ b/std/math/complex/conj.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/cos.zig b/std/math/complex/cos.zig
index 658d19c3b6ecac46dac8c0d42ba036daac5f3ce5..71f9603c75841ad017d368b531c9f5cd01226860 100644
--- a/std/math/complex/cos.zig
+++ b/std/math/complex/cos.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/cosh.zig b/std/math/complex/cosh.zig
index 5ce10b03f8396caf592252a401c8ac7be5663f25..9806e411709a3130810e94f3aa950918f3114be5 100644
--- a/std/math/complex/cosh.zig
+++ b/std/math/complex/cosh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/exp.zig b/std/math/complex/exp.zig
index 9ded698d088eda5fe4b2a99f16cc4866a4a1e60d..c74ac2fc08fc4359a23296e6b462a71466c05c2c 100644
--- a/std/math/complex/exp.zig
+++ b/std/math/complex/exp.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/index.zig b/std/math/complex/index.zig
deleted file mode 100644
index ffbf14d83e68fa926d0cb62fc66b38ecfa02c546..0000000000000000000000000000000000000000
--- a/std/math/complex/index.zig
+++ /dev/null
@@ -1,171 +0,0 @@
-const std = @import("../../index.zig");
-const testing = std.testing;
-const math = std.math;
-
-pub const abs = @import("abs.zig").abs;
-pub const acosh = @import("acosh.zig").acosh;
-pub const acos = @import("acos.zig").acos;
-pub const arg = @import("arg.zig").arg;
-pub const asinh = @import("asinh.zig").asinh;
-pub const asin = @import("asin.zig").asin;
-pub const atanh = @import("atanh.zig").atanh;
-pub const atan = @import("atan.zig").atan;
-pub const conj = @import("conj.zig").conj;
-pub const cosh = @import("cosh.zig").cosh;
-pub const cos = @import("cos.zig").cos;
-pub const exp = @import("exp.zig").exp;
-pub const log = @import("log.zig").log;
-pub const pow = @import("pow.zig").pow;
-pub const proj = @import("proj.zig").proj;
-pub const sinh = @import("sinh.zig").sinh;
-pub const sin = @import("sin.zig").sin;
-pub const sqrt = @import("sqrt.zig").sqrt;
-pub const tanh = @import("tanh.zig").tanh;
-pub const tan = @import("tan.zig").tan;
-
-pub fn Complex(comptime T: type) type {
- return struct {
- const Self = @This();
-
- re: T,
- im: T,
-
- pub fn new(re: T, im: T) Self {
- return Self{
- .re = re,
- .im = im,
- };
- }
-
- pub fn add(self: Self, other: Self) Self {
- return Self{
- .re = self.re + other.re,
- .im = self.im + other.im,
- };
- }
-
- pub fn sub(self: Self, other: Self) Self {
- return Self{
- .re = self.re - other.re,
- .im = self.im - other.im,
- };
- }
-
- pub fn mul(self: Self, other: Self) Self {
- return Self{
- .re = self.re * other.re - self.im * other.im,
- .im = self.im * other.re + self.re * other.im,
- };
- }
-
- pub fn div(self: Self, other: Self) Self {
- const re_num = self.re * other.re + self.im * other.im;
- const im_num = self.im * other.re - self.re * other.im;
- const den = other.re * other.re + other.im * other.im;
-
- return Self{
- .re = re_num / den,
- .im = im_num / den,
- };
- }
-
- pub fn conjugate(self: Self) Self {
- return Self{
- .re = self.re,
- .im = -self.im,
- };
- }
-
- pub fn reciprocal(self: Self) Self {
- const m = self.re * self.re + self.im * self.im;
- return Self{
- .re = self.re / m,
- .im = -self.im / m,
- };
- }
-
- pub fn magnitude(self: Self) T {
- return math.sqrt(self.re * self.re + self.im * self.im);
- }
- };
-}
-
-const epsilon = 0.0001;
-
-test "complex.add" {
- const a = Complex(f32).new(5, 3);
- const b = Complex(f32).new(2, 7);
- const c = a.add(b);
-
- testing.expect(c.re == 7 and c.im == 10);
-}
-
-test "complex.sub" {
- const a = Complex(f32).new(5, 3);
- const b = Complex(f32).new(2, 7);
- const c = a.sub(b);
-
- testing.expect(c.re == 3 and c.im == -4);
-}
-
-test "complex.mul" {
- const a = Complex(f32).new(5, 3);
- const b = Complex(f32).new(2, 7);
- const c = a.mul(b);
-
- testing.expect(c.re == -11 and c.im == 41);
-}
-
-test "complex.div" {
- const a = Complex(f32).new(5, 3);
- const b = Complex(f32).new(2, 7);
- const c = a.div(b);
-
- testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and
- math.approxEq(f32, c.im, f32(-29) / 53, epsilon));
-}
-
-test "complex.conjugate" {
- const a = Complex(f32).new(5, 3);
- const c = a.conjugate();
-
- testing.expect(c.re == 5 and c.im == -3);
-}
-
-test "complex.reciprocal" {
- const a = Complex(f32).new(5, 3);
- const c = a.reciprocal();
-
- testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and
- math.approxEq(f32, c.im, f32(-3) / 34, epsilon));
-}
-
-test "complex.magnitude" {
- const a = Complex(f32).new(5, 3);
- const c = a.magnitude();
-
- testing.expect(math.approxEq(f32, c, 5.83095, epsilon));
-}
-
-test "complex.cmath" {
- _ = @import("abs.zig");
- _ = @import("acosh.zig");
- _ = @import("acos.zig");
- _ = @import("arg.zig");
- _ = @import("asinh.zig");
- _ = @import("asin.zig");
- _ = @import("atanh.zig");
- _ = @import("atan.zig");
- _ = @import("conj.zig");
- _ = @import("cosh.zig");
- _ = @import("cos.zig");
- _ = @import("exp.zig");
- _ = @import("log.zig");
- _ = @import("pow.zig");
- _ = @import("proj.zig");
- _ = @import("sinh.zig");
- _ = @import("sin.zig");
- _ = @import("sqrt.zig");
- _ = @import("tanh.zig");
- _ = @import("tan.zig");
-}
diff --git a/std/math/complex/ldexp.zig b/std/math/complex/ldexp.zig
index e919ef6bec5728b03e3e0c1a658baf74f9d01ee1..6b4306bf77277e944c31065ee179ed8abd9f83db 100644
--- a/std/math/complex/ldexp.zig
+++ b/std/math/complex/ldexp.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const debug = std.debug;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/log.zig b/std/math/complex/log.zig
index 360bb7d21ea624610c4c6cc08de89bec534fc6a7..2b43a6970f5b09701196ff8fd7b0e86db3519c3b 100644
--- a/std/math/complex/log.zig
+++ b/std/math/complex/log.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/pow.zig b/std/math/complex/pow.zig
index bd625626c8790ff428e25455253005895a6ddad8..9174bb36260aca9933b1c2118524bda535c46d11 100644
--- a/std/math/complex/pow.zig
+++ b/std/math/complex/pow.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/proj.zig b/std/math/complex/proj.zig
index d31006129e2f7edfd515a9414e5b379d3aa8eb4b..aadcff6ff664e4da4636a2ff01934f9ff2b42ea1 100644
--- a/std/math/complex/proj.zig
+++ b/std/math/complex/proj.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/sin.zig b/std/math/complex/sin.zig
index 9d54ab0969691673589e893068f84faca065112b..049631f31e361557a4e22898316f2fdb1ba140cb 100644
--- a/std/math/complex/sin.zig
+++ b/std/math/complex/sin.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/sinh.zig b/std/math/complex/sinh.zig
index 469ea6067a3f3900e0f15616e215c2026ea28fad..0b656e53545dfd12123f2cc22803faea2e62b298 100644
--- a/std/math/complex/sinh.zig
+++ b/std/math/complex/sinh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/sqrt.zig b/std/math/complex/sqrt.zig
index 60f6061baab09f6e2e2d390cb0ca9342c5661d51..e935d0b238566e9dcfafec8e61780369195c7a77 100644
--- a/std/math/complex/sqrt.zig
+++ b/std/math/complex/sqrt.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/tan.zig b/std/math/complex/tan.zig
index db345805985b9e64d672d8178d4ef1cc3ea4bc1b..45e2873eb6ee5460e737888e39086107cb31dd85 100644
--- a/std/math/complex/tan.zig
+++ b/std/math/complex/tan.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/complex/tanh.zig b/std/math/complex/tanh.zig
index 03ab431312686e155dd18354bde966c6daeb0ed2..de905ee3f692432c4c8d2aa7a47c5da7ee2a98e9 100644
--- a/std/math/complex/tanh.zig
+++ b/std/math/complex/tanh.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const testing = std.testing;
const math = std.math;
const cmath = math.complex;
diff --git a/std/math/copysign.zig b/std/math/copysign.zig
index dbf8f6e1ef911e8431d4d7565b095243c5c49b07..ff8140b3ab9efa23fb3b9725b00edf165f1d78da 100644
--- a/std/math/copysign.zig
+++ b/std/math/copysign.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/cos.zig b/std/math/cos.zig
index 7783ddc09be9139600d781882ab7b1ba2b5a5517..947948289490af680df2a582cdb1cbce1ad73727 100644
--- a/std/math/cos.zig
+++ b/std/math/cos.zig
@@ -4,7 +4,7 @@
// - cos(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/cosh.zig b/std/math/cosh.zig
index 57c5eef828484700c4c3810a8f028b91aadb8587..eb3082e5fa179ac605ca911d607c8e84688c76ad 100644
--- a/std/math/cosh.zig
+++ b/std/math/cosh.zig
@@ -5,7 +5,7 @@
// - cosh(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expo2 = @import("expo2.zig").expo2;
const expect = std.testing.expect;
diff --git a/std/math/exp.zig b/std/math/exp.zig
index cf8fd62d806e9aff92110a5e90813e7999b5cbd6..aabccffd0b4ed59d0996f290ab9a5c645ea5faa5 100644
--- a/std/math/exp.zig
+++ b/std/math/exp.zig
@@ -3,7 +3,7 @@
// - exp(+inf) = +inf
// - exp(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const assert = std.debug.assert;
const builtin = @import("builtin");
diff --git a/std/math/exp2.zig b/std/math/exp2.zig
index ba0001a09adb8aaa62a2c66f7c2917dc14a6bd59..392d45bf68baec91cd2b0a35d0f7a7cdf22a677c 100644
--- a/std/math/exp2.zig
+++ b/std/math/exp2.zig
@@ -3,7 +3,7 @@
// - exp2(+inf) = +inf
// - exp2(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/expm1.zig b/std/math/expm1.zig
index ba00ec2561966b2f23e6343ff55e772a76ded387..b83cc3e82e854e4c536dc178f9f37e310586be06 100644
--- a/std/math/expm1.zig
+++ b/std/math/expm1.zig
@@ -5,7 +5,7 @@
// - expm1(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/expo2.zig b/std/math/expo2.zig
index 15b80c710cc3d9158de94a2f557f7037da685cb7..57e2bf34c940734f559f3b8c7b4466da4611b50f 100644
--- a/std/math/expo2.zig
+++ b/std/math/expo2.zig
@@ -1,4 +1,4 @@
-const math = @import("index.zig");
+const math = @import("../math.zig");
pub fn expo2(x: var) @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/fabs.zig b/std/math/fabs.zig
index a605f4f33f048cdd4cff4bd481fce035b9d39fb5..e30f788ae736053325fa0f533300a231a38d40bd 100644
--- a/std/math/fabs.zig
+++ b/std/math/fabs.zig
@@ -3,7 +3,7 @@
// - fabs(+-inf) = +inf
// - fabs(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/floor.zig b/std/math/floor.zig
index c7c12e37bad38c4429177ba69c97d3630a469682..ab45a8fee7462967ae5eed1b61d4b75cfe306a8b 100644
--- a/std/math/floor.zig
+++ b/std/math/floor.zig
@@ -6,7 +6,7 @@
const builtin = @import("builtin");
const expect = std.testing.expect;
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
pub fn floor(x: var) @typeOf(x) {
diff --git a/std/math/fma.zig b/std/math/fma.zig
index b084cf3cbde2f106774e1d82d0c113caa6c9a28d..a317bc96de08cc07a793223fd74145dba039da6e 100644
--- a/std/math/fma.zig
+++ b/std/math/fma.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/frexp.zig b/std/math/frexp.zig
index 35f3e081a9036a721de24dad3f191ef623a531f9..35eec315d971bd9985e8a1a611aeeffb0e8019ee 100644
--- a/std/math/frexp.zig
+++ b/std/math/frexp.zig
@@ -4,7 +4,7 @@
// - frexp(+-inf) = +-inf, 0
// - frexp(nan) = nan, undefined
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/hypot.zig b/std/math/hypot.zig
index dea11e0a61053af2a0d06c35f23c94b6bcdf0967..fddbe7c0688d22572606c50c7aa7b7619cb0c89b 100644
--- a/std/math/hypot.zig
+++ b/std/math/hypot.zig
@@ -5,7 +5,7 @@
// - hypot(nan, y) = nan
// - hypot(x, nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig
index e7b64853570c99e99daa0c23052fcae3ebe4a104..2dfd42a62c431ac1babc4cf81c41a08e1fe6cbeb 100644
--- a/std/math/ilogb.zig
+++ b/std/math/ilogb.zig
@@ -4,7 +4,7 @@
// - ilogb(0) = maxInt(i32)
// - ilogb(nan) = maxInt(i32)
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/index.zig b/std/math/index.zig
deleted file mode 100644
index 20648139b81a7daba5579bbc66aa251524b01838..0000000000000000000000000000000000000000
--- a/std/math/index.zig
+++ /dev/null
@@ -1,797 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("../index.zig");
-const TypeId = builtin.TypeId;
-const assert = std.debug.assert;
-const testing = std.testing;
-
-pub const e = 2.71828182845904523536028747135266249775724709369995;
-pub const pi = 3.14159265358979323846264338327950288419716939937510;
-
-// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
-pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001));
-pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000));
-pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
-pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000));
-pub const f128_toint = 1.0 / f128_epsilon;
-
-// float.h details
-pub const f64_true_min = 4.94065645841246544177e-324;
-pub const f64_min = 2.2250738585072014e-308;
-pub const f64_max = 1.79769313486231570815e+308;
-pub const f64_epsilon = 2.22044604925031308085e-16;
-pub const f64_toint = 1.0 / f64_epsilon;
-
-pub const f32_true_min = 1.40129846432481707092e-45;
-pub const f32_min = 1.17549435082228750797e-38;
-pub const f32_max = 3.40282346638528859812e+38;
-pub const f32_epsilon = 1.1920928955078125e-07;
-pub const f32_toint = 1.0 / f32_epsilon;
-
-pub const f16_true_min = 0.000000059604644775390625; // 2**-24
-pub const f16_min = 0.00006103515625; // 2**-14
-pub const f16_max = 65504;
-pub const f16_epsilon = 0.0009765625; // 2**-10
-pub const f16_toint = 1.0 / f16_epsilon;
-
-pub const nan_u16 = u16(0x7C01);
-pub const nan_f16 = @bitCast(f16, nan_u16);
-
-pub const inf_u16 = u16(0x7C00);
-pub const inf_f16 = @bitCast(f16, inf_u16);
-
-pub const nan_u32 = u32(0x7F800001);
-pub const nan_f32 = @bitCast(f32, nan_u32);
-
-pub const inf_u32 = u32(0x7F800000);
-pub const inf_f32 = @bitCast(f32, inf_u32);
-
-pub const nan_u64 = u64(0x7FF << 52) | 1;
-pub const nan_f64 = @bitCast(f64, nan_u64);
-
-pub const inf_u64 = u64(0x7FF << 52);
-pub const inf_f64 = @bitCast(f64, inf_u64);
-
-pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
-pub const nan_f128 = @bitCast(f128, nan_u128);
-
-pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
-pub const inf_f128 = @bitCast(f128, inf_u128);
-
-pub const nan = @import("nan.zig").nan;
-pub const snan = @import("nan.zig").snan;
-pub const inf = @import("inf.zig").inf;
-
-pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
- assert(@typeId(T) == TypeId.Float);
- return fabs(x - y) < epsilon;
-}
-
-// TODO: Hide the following in an internal module.
-pub fn forceEval(value: var) void {
- const T = @typeOf(value);
- switch (T) {
- f16 => {
- var x: f16 = undefined;
- const p = @ptrCast(*volatile f16, &x);
- p.* = x;
- },
- f32 => {
- var x: f32 = undefined;
- const p = @ptrCast(*volatile f32, &x);
- p.* = x;
- },
- f64 => {
- var x: f64 = undefined;
- const p = @ptrCast(*volatile f64, &x);
- p.* = x;
- },
- else => {
- @compileError("forceEval not implemented for " ++ @typeName(T));
- },
- }
-}
-
-pub fn raiseInvalid() void {
- // Raise INVALID fpu exception
-}
-
-pub fn raiseUnderflow() void {
- // Raise UNDERFLOW fpu exception
-}
-
-pub fn raiseOverflow() void {
- // Raise OVERFLOW fpu exception
-}
-
-pub fn raiseInexact() void {
- // Raise INEXACT fpu exception
-}
-
-pub fn raiseDivByZero() void {
- // Raise INEXACT fpu exception
-}
-
-pub const isNan = @import("isnan.zig").isNan;
-pub const isSignalNan = @import("isnan.zig").isSignalNan;
-pub const fabs = @import("fabs.zig").fabs;
-pub const ceil = @import("ceil.zig").ceil;
-pub const floor = @import("floor.zig").floor;
-pub const trunc = @import("trunc.zig").trunc;
-pub const round = @import("round.zig").round;
-pub const frexp = @import("frexp.zig").frexp;
-pub const frexp32_result = @import("frexp.zig").frexp32_result;
-pub const frexp64_result = @import("frexp.zig").frexp64_result;
-pub const modf = @import("modf.zig").modf;
-pub const modf32_result = @import("modf.zig").modf32_result;
-pub const modf64_result = @import("modf.zig").modf64_result;
-pub const copysign = @import("copysign.zig").copysign;
-pub const isFinite = @import("isfinite.zig").isFinite;
-pub const isInf = @import("isinf.zig").isInf;
-pub const isPositiveInf = @import("isinf.zig").isPositiveInf;
-pub const isNegativeInf = @import("isinf.zig").isNegativeInf;
-pub const isNormal = @import("isnormal.zig").isNormal;
-pub const signbit = @import("signbit.zig").signbit;
-pub const scalbn = @import("scalbn.zig").scalbn;
-pub const pow = @import("pow.zig").pow;
-pub const powi = @import("powi.zig").powi;
-pub const sqrt = @import("sqrt.zig").sqrt;
-pub const cbrt = @import("cbrt.zig").cbrt;
-pub const acos = @import("acos.zig").acos;
-pub const asin = @import("asin.zig").asin;
-pub const atan = @import("atan.zig").atan;
-pub const atan2 = @import("atan2.zig").atan2;
-pub const hypot = @import("hypot.zig").hypot;
-pub const exp = @import("exp.zig").exp;
-pub const exp2 = @import("exp2.zig").exp2;
-pub const expm1 = @import("expm1.zig").expm1;
-pub const ilogb = @import("ilogb.zig").ilogb;
-pub const ln = @import("ln.zig").ln;
-pub const log = @import("log.zig").log;
-pub const log2 = @import("log2.zig").log2;
-pub const log10 = @import("log10.zig").log10;
-pub const log1p = @import("log1p.zig").log1p;
-pub const fma = @import("fma.zig").fma;
-pub const asinh = @import("asinh.zig").asinh;
-pub const acosh = @import("acosh.zig").acosh;
-pub const atanh = @import("atanh.zig").atanh;
-pub const sinh = @import("sinh.zig").sinh;
-pub const cosh = @import("cosh.zig").cosh;
-pub const tanh = @import("tanh.zig").tanh;
-pub const cos = @import("cos.zig").cos;
-pub const sin = @import("sin.zig").sin;
-pub const tan = @import("tan.zig").tan;
-
-pub const complex = @import("complex/index.zig");
-pub const Complex = complex.Complex;
-
-pub const big = @import("big/index.zig");
-
-test "math" {
- _ = @import("nan.zig");
- _ = @import("isnan.zig");
- _ = @import("fabs.zig");
- _ = @import("ceil.zig");
- _ = @import("floor.zig");
- _ = @import("trunc.zig");
- _ = @import("round.zig");
- _ = @import("frexp.zig");
- _ = @import("modf.zig");
- _ = @import("copysign.zig");
- _ = @import("isfinite.zig");
- _ = @import("isinf.zig");
- _ = @import("isnormal.zig");
- _ = @import("signbit.zig");
- _ = @import("scalbn.zig");
- _ = @import("pow.zig");
- _ = @import("powi.zig");
- _ = @import("sqrt.zig");
- _ = @import("cbrt.zig");
- _ = @import("acos.zig");
- _ = @import("asin.zig");
- _ = @import("atan.zig");
- _ = @import("atan2.zig");
- _ = @import("hypot.zig");
- _ = @import("exp.zig");
- _ = @import("exp2.zig");
- _ = @import("expm1.zig");
- _ = @import("ilogb.zig");
- _ = @import("ln.zig");
- _ = @import("log.zig");
- _ = @import("log2.zig");
- _ = @import("log10.zig");
- _ = @import("log1p.zig");
- _ = @import("fma.zig");
- _ = @import("asinh.zig");
- _ = @import("acosh.zig");
- _ = @import("atanh.zig");
- _ = @import("sinh.zig");
- _ = @import("cosh.zig");
- _ = @import("tanh.zig");
- _ = @import("sin.zig");
- _ = @import("cos.zig");
- _ = @import("tan.zig");
-
- _ = @import("complex/index.zig");
-
- _ = @import("big/index.zig");
-}
-
-pub fn floatMantissaBits(comptime T: type) comptime_int {
- assert(@typeId(T) == builtin.TypeId.Float);
-
- return switch (T.bit_count) {
- 16 => 10,
- 32 => 23,
- 64 => 52,
- 80 => 64,
- 128 => 112,
- else => @compileError("unknown floating point type " ++ @typeName(T)),
- };
-}
-
-pub fn floatExponentBits(comptime T: type) comptime_int {
- assert(@typeId(T) == builtin.TypeId.Float);
-
- return switch (T.bit_count) {
- 16 => 5,
- 32 => 8,
- 64 => 11,
- 80 => 15,
- 128 => 15,
- else => @compileError("unknown floating point type " ++ @typeName(T)),
- };
-}
-
-pub fn min(x: var, y: var) @typeOf(x + y) {
- return if (x < y) x else y;
-}
-
-test "math.min" {
- testing.expect(min(i32(-1), i32(2)) == -1);
-}
-
-pub fn max(x: var, y: var) @typeOf(x + y) {
- return if (x > y) x else y;
-}
-
-test "math.max" {
- testing.expect(max(i32(-1), i32(2)) == 2);
-}
-
-pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
- var answer: T = undefined;
- return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
-}
-
-pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
- var answer: T = undefined;
- return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
-}
-
-pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
- var answer: T = undefined;
- return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
-}
-
-pub fn negate(x: var) !@typeOf(x) {
- return sub(@typeOf(x), 0, x);
-}
-
-pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
- var answer: T = undefined;
- return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
-}
-
-/// Shifts left. Overflowed bits are truncated.
-/// A negative shift amount results in a right shift.
-pub fn shl(comptime T: type, a: T, shift_amt: var) T {
- const abs_shift_amt = absCast(shift_amt);
- const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
-
- if (@typeOf(shift_amt).is_signed) {
- if (shift_amt >= 0) {
- return a << casted_shift_amt;
- } else {
- return a >> casted_shift_amt;
- }
- }
-
- return a << casted_shift_amt;
-}
-
-test "math.shl" {
- testing.expect(shl(u8, 0b11111111, usize(3)) == 0b11111000);
- testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
- testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
- testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111);
-}
-
-/// Shifts right. Overflowed bits are truncated.
-/// A negative shift amount results in a lefft shift.
-pub fn shr(comptime T: type, a: T, shift_amt: var) T {
- const abs_shift_amt = absCast(shift_amt);
- const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
-
- if (@typeOf(shift_amt).is_signed) {
- if (shift_amt >= 0) {
- return a >> casted_shift_amt;
- } else {
- return a << casted_shift_amt;
- }
- }
-
- return a >> casted_shift_amt;
-}
-
-test "math.shr" {
- testing.expect(shr(u8, 0b11111111, usize(3)) == 0b00011111);
- testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
- testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
- testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
-}
-
-/// Rotates right. Only unsigned values can be rotated.
-/// Negative shift values results in shift modulo the bit count.
-pub fn rotr(comptime T: type, x: T, r: var) T {
- if (T.is_signed) {
- @compileError("cannot rotate signed integer");
- } else {
- const ar = @mod(r, T.bit_count);
- return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
- }
-}
-
-test "math.rotr" {
- testing.expect(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
- testing.expect(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
- testing.expect(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
- testing.expect(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
- testing.expect(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
-}
-
-/// Rotates left. Only unsigned values can be rotated.
-/// Negative shift values results in shift modulo the bit count.
-pub fn rotl(comptime T: type, x: T, r: var) T {
- if (T.is_signed) {
- @compileError("cannot rotate signed integer");
- } else {
- const ar = @mod(r, T.bit_count);
- return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
- }
-}
-
-test "math.rotl" {
- testing.expect(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
- testing.expect(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
- testing.expect(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
- testing.expect(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
- testing.expect(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
-}
-
-pub fn Log2Int(comptime T: type) type {
- // comptime ceil log2
- comptime var count = 0;
- comptime var s = T.bit_count - 1;
- inline while (s != 0) : (s >>= 1) {
- count += 1;
- }
-
- return @IntType(false, count);
-}
-
-pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
- assert(from <= to);
- if (from == 0 and to == 0) {
- return u0;
- }
- const is_signed = from < 0;
- const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
- const base = log2(largest_positive_integer);
- const upper = (1 << base) - 1;
- var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
- if (is_signed) {
- magnitude_bits += 1;
- }
- return @IntType(is_signed, magnitude_bits);
-}
-
-test "math.IntFittingRange" {
- testing.expect(IntFittingRange(0, 0) == u0);
- testing.expect(IntFittingRange(0, 1) == u1);
- testing.expect(IntFittingRange(0, 2) == u2);
- testing.expect(IntFittingRange(0, 3) == u2);
- testing.expect(IntFittingRange(0, 4) == u3);
- testing.expect(IntFittingRange(0, 7) == u3);
- testing.expect(IntFittingRange(0, 8) == u4);
- testing.expect(IntFittingRange(0, 9) == u4);
- testing.expect(IntFittingRange(0, 15) == u4);
- testing.expect(IntFittingRange(0, 16) == u5);
- testing.expect(IntFittingRange(0, 17) == u5);
- testing.expect(IntFittingRange(0, 4095) == u12);
- testing.expect(IntFittingRange(2000, 4095) == u12);
- testing.expect(IntFittingRange(0, 4096) == u13);
- testing.expect(IntFittingRange(2000, 4096) == u13);
- testing.expect(IntFittingRange(0, 4097) == u13);
- testing.expect(IntFittingRange(2000, 4097) == u13);
- testing.expect(IntFittingRange(0, 123456789123456798123456789) == u87);
- testing.expect(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
-
- testing.expect(IntFittingRange(-1, -1) == i1);
- testing.expect(IntFittingRange(-1, 0) == i1);
- testing.expect(IntFittingRange(-1, 1) == i2);
- testing.expect(IntFittingRange(-2, -2) == i2);
- testing.expect(IntFittingRange(-2, -1) == i2);
- testing.expect(IntFittingRange(-2, 0) == i2);
- testing.expect(IntFittingRange(-2, 1) == i2);
- testing.expect(IntFittingRange(-2, 2) == i3);
- testing.expect(IntFittingRange(-1, 2) == i3);
- testing.expect(IntFittingRange(-1, 3) == i3);
- testing.expect(IntFittingRange(-1, 4) == i4);
- testing.expect(IntFittingRange(-1, 7) == i4);
- testing.expect(IntFittingRange(-1, 8) == i5);
- testing.expect(IntFittingRange(-1, 9) == i5);
- testing.expect(IntFittingRange(-1, 15) == i5);
- testing.expect(IntFittingRange(-1, 16) == i6);
- testing.expect(IntFittingRange(-1, 17) == i6);
- testing.expect(IntFittingRange(-1, 4095) == i13);
- testing.expect(IntFittingRange(-4096, 4095) == i13);
- testing.expect(IntFittingRange(-1, 4096) == i14);
- testing.expect(IntFittingRange(-4097, 4095) == i14);
- testing.expect(IntFittingRange(-1, 4097) == i14);
- testing.expect(IntFittingRange(-1, 123456789123456798123456789) == i88);
- testing.expect(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
-}
-
-test "math overflow functions" {
- testOverflow();
- comptime testOverflow();
-}
-
-fn testOverflow() void {
- testing.expect((mul(i32, 3, 4) catch unreachable) == 12);
- testing.expect((add(i32, 3, 4) catch unreachable) == 7);
- testing.expect((sub(i32, 3, 4) catch unreachable) == -1);
- testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
-}
-
-pub fn absInt(x: var) !@typeOf(x) {
- const T = @typeOf(x);
- comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
- comptime assert(T.is_signed); // must pass a signed integer to absInt
-
- if (x == minInt(@typeOf(x))) {
- return error.Overflow;
- } else {
- @setRuntimeSafety(false);
- return if (x < 0) -x else x;
- }
-}
-
-test "math.absInt" {
- testAbsInt();
- comptime testAbsInt();
-}
-fn testAbsInt() void {
- testing.expect((absInt(i32(-10)) catch unreachable) == 10);
- testing.expect((absInt(i32(10)) catch unreachable) == 10);
-}
-
-pub const absFloat = @import("fabs.zig").fabs;
-
-pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
- @setRuntimeSafety(false);
- if (denominator == 0) return error.DivisionByZero;
- if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
- return @divTrunc(numerator, denominator);
-}
-
-test "math.divTrunc" {
- testDivTrunc();
- comptime testDivTrunc();
-}
-fn testDivTrunc() void {
- testing.expect((divTrunc(i32, 5, 3) catch unreachable) == 1);
- testing.expect((divTrunc(i32, -5, 3) catch unreachable) == -1);
- testing.expectError(error.DivisionByZero, divTrunc(i8, -5, 0));
- testing.expectError(error.Overflow, divTrunc(i8, -128, -1));
-
- testing.expect((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0);
- testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0);
-}
-
-pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T {
- @setRuntimeSafety(false);
- if (denominator == 0) return error.DivisionByZero;
- if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
- return @divFloor(numerator, denominator);
-}
-
-test "math.divFloor" {
- testDivFloor();
- comptime testDivFloor();
-}
-fn testDivFloor() void {
- testing.expect((divFloor(i32, 5, 3) catch unreachable) == 1);
- testing.expect((divFloor(i32, -5, 3) catch unreachable) == -2);
- testing.expectError(error.DivisionByZero, divFloor(i8, -5, 0));
- testing.expectError(error.Overflow, divFloor(i8, -128, -1));
-
- testing.expect((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0);
- testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0);
-}
-
-pub fn divExact(comptime T: type, numerator: T, denominator: T) !T {
- @setRuntimeSafety(false);
- if (denominator == 0) return error.DivisionByZero;
- if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow;
- const result = @divTrunc(numerator, denominator);
- if (result * denominator != numerator) return error.UnexpectedRemainder;
- return result;
-}
-
-test "math.divExact" {
- testDivExact();
- comptime testDivExact();
-}
-fn testDivExact() void {
- testing.expect((divExact(i32, 10, 5) catch unreachable) == 2);
- testing.expect((divExact(i32, -10, 5) catch unreachable) == -2);
- testing.expectError(error.DivisionByZero, divExact(i8, -5, 0));
- testing.expectError(error.Overflow, divExact(i8, -128, -1));
- testing.expectError(error.UnexpectedRemainder, divExact(i32, 5, 2));
-
- testing.expect((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0);
- testing.expect((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0);
- testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0));
-}
-
-pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
- @setRuntimeSafety(false);
- if (denominator == 0) return error.DivisionByZero;
- if (denominator < 0) return error.NegativeDenominator;
- return @mod(numerator, denominator);
-}
-
-test "math.mod" {
- testMod();
- comptime testMod();
-}
-fn testMod() void {
- testing.expect((mod(i32, -5, 3) catch unreachable) == 1);
- testing.expect((mod(i32, 5, 3) catch unreachable) == 2);
- testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));
- testing.expectError(error.DivisionByZero, mod(i32, 10, 0));
-
- testing.expect((mod(f32, -5, 3) catch unreachable) == 1);
- testing.expect((mod(f32, 5, 3) catch unreachable) == 2);
- testing.expectError(error.NegativeDenominator, mod(f32, 10, -1));
- testing.expectError(error.DivisionByZero, mod(f32, 10, 0));
-}
-
-pub fn rem(comptime T: type, numerator: T, denominator: T) !T {
- @setRuntimeSafety(false);
- if (denominator == 0) return error.DivisionByZero;
- if (denominator < 0) return error.NegativeDenominator;
- return @rem(numerator, denominator);
-}
-
-test "math.rem" {
- testRem();
- comptime testRem();
-}
-fn testRem() void {
- testing.expect((rem(i32, -5, 3) catch unreachable) == -2);
- testing.expect((rem(i32, 5, 3) catch unreachable) == 2);
- testing.expectError(error.NegativeDenominator, rem(i32, 10, -1));
- testing.expectError(error.DivisionByZero, rem(i32, 10, 0));
-
- testing.expect((rem(f32, -5, 3) catch unreachable) == -2);
- testing.expect((rem(f32, 5, 3) catch unreachable) == 2);
- testing.expectError(error.NegativeDenominator, rem(f32, 10, -1));
- testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
-}
-
-/// Returns the absolute value of the integer parameter.
-/// Result is an unsigned integer.
-pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) {
- const uint = @IntType(false, @typeOf(x).bit_count);
- if (x >= 0) return @intCast(uint, x);
-
- return @intCast(uint, -(x + 1)) + 1;
-}
-
-test "math.absCast" {
- testing.expect(absCast(i32(-999)) == 999);
- testing.expect(@typeOf(absCast(i32(-999))) == u32);
-
- testing.expect(absCast(i32(999)) == 999);
- testing.expect(@typeOf(absCast(i32(999))) == u32);
-
- testing.expect(absCast(i32(minInt(i32))) == -minInt(i32));
- testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32);
-}
-
-/// Returns the negation of the integer parameter.
-/// Result is a signed integer.
-pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) {
- if (@typeOf(x).is_signed) return negate(x);
-
- const int = @IntType(true, @typeOf(x).bit_count);
- if (x > -minInt(int)) return error.Overflow;
-
- if (x == -minInt(int)) return minInt(int);
-
- return -@intCast(int, x);
-}
-
-test "math.negateCast" {
- testing.expect((negateCast(u32(999)) catch unreachable) == -999);
- testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32);
-
- testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32));
- testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32);
-
- testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10)));
-}
-
-/// Cast an integer to a different integer type. If the value doesn't fit,
-/// return an error.
-pub fn cast(comptime T: type, x: var) (error{Overflow}!T) {
- comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer
- comptime assert(@typeId(@typeOf(x)) == builtin.TypeId.Int); // must pass an integer
- if (maxInt(@typeOf(x)) > maxInt(T) and x > maxInt(T)) {
- return error.Overflow;
- } else if (minInt(@typeOf(x)) < minInt(T) and x < minInt(T)) {
- return error.Overflow;
- } else {
- return @intCast(T, x);
- }
-}
-
-test "math.cast" {
- testing.expectError(error.Overflow, cast(u8, u32(300)));
- testing.expectError(error.Overflow, cast(i8, i32(-200)));
- testing.expectError(error.Overflow, cast(u8, i8(-1)));
- testing.expectError(error.Overflow, cast(u64, i8(-1)));
-
- testing.expect((try cast(u8, u32(255))) == u8(255));
- testing.expect(@typeOf(try cast(u8, u32(255))) == u8);
-}
-
-pub const AlignCastError = error{UnalignedMemory};
-
-/// Align cast a pointer but return an error if it's the wrong alignment
-pub fn alignCast(comptime alignment: u29, ptr: var) AlignCastError!@typeOf(@alignCast(alignment, ptr)) {
- const addr = @ptrToInt(ptr);
- if (addr % alignment != 0) {
- return error.UnalignedMemory;
- }
- return @alignCast(alignment, ptr);
-}
-
-pub fn floorPowerOfTwo(comptime T: type, value: T) T {
- var x = value;
-
- comptime var i = 1;
- inline while (T.bit_count > i) : (i *= 2) {
- x |= (x >> i);
- }
-
- return x - (x >> 1);
-}
-
-test "math.floorPowerOfTwo" {
- testFloorPowerOfTwo();
- comptime testFloorPowerOfTwo();
-}
-
-pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
- assert(x != 0);
- return @intCast(Log2Int(T), T.bit_count - 1 - @clz(x));
-}
-
-pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) {
- assert(x != 0);
- const log2_val = log2_int(T, x);
- if (T(1) << log2_val == x)
- return log2_val;
- return log2_val + 1;
-}
-
-test "std.math.log2_int_ceil" {
- testing.expect(log2_int_ceil(u32, 1) == 0);
- testing.expect(log2_int_ceil(u32, 2) == 1);
- testing.expect(log2_int_ceil(u32, 3) == 2);
- testing.expect(log2_int_ceil(u32, 4) == 2);
- testing.expect(log2_int_ceil(u32, 5) == 3);
- testing.expect(log2_int_ceil(u32, 6) == 3);
- testing.expect(log2_int_ceil(u32, 7) == 3);
- testing.expect(log2_int_ceil(u32, 8) == 3);
- testing.expect(log2_int_ceil(u32, 9) == 4);
- testing.expect(log2_int_ceil(u32, 10) == 4);
-}
-
-fn testFloorPowerOfTwo() void {
- testing.expect(floorPowerOfTwo(u32, 63) == 32);
- testing.expect(floorPowerOfTwo(u32, 64) == 64);
- testing.expect(floorPowerOfTwo(u32, 65) == 64);
- testing.expect(floorPowerOfTwo(u4, 7) == 4);
- testing.expect(floorPowerOfTwo(u4, 8) == 8);
- testing.expect(floorPowerOfTwo(u4, 9) == 8);
-}
-
-pub fn lossyCast(comptime T: type, value: var) T {
- switch (@typeInfo(@typeOf(value))) {
- builtin.TypeId.Int => return @intToFloat(T, value),
- builtin.TypeId.Float => return @floatCast(T, value),
- builtin.TypeId.ComptimeInt => return T(value),
- builtin.TypeId.ComptimeFloat => return T(value),
- else => @compileError("bad type"),
- }
-}
-
-test "math.f64_min" {
- const f64_min_u64 = 0x0010000000000000;
- const fmin: f64 = f64_min;
- testing.expect(@bitCast(u64, fmin) == f64_min_u64);
-}
-
-pub fn maxInt(comptime T: type) comptime_int {
- const info = @typeInfo(T);
- const bit_count = comptime_int(info.Int.bits); // TODO #1683
- if (bit_count == 0) return 0;
- return (1 << (bit_count - @boolToInt(info.Int.is_signed))) - 1;
-}
-
-pub fn minInt(comptime T: type) comptime_int {
- const info = @typeInfo(T);
- const bit_count = comptime_int(info.Int.bits); // TODO #1683
- if (!info.Int.is_signed) return 0;
- if (bit_count == 0) return 0;
- return -(1 << (bit_count - 1));
-}
-
-test "minInt and maxInt" {
- testing.expect(maxInt(u0) == 0);
- testing.expect(maxInt(u1) == 1);
- testing.expect(maxInt(u8) == 255);
- testing.expect(maxInt(u16) == 65535);
- testing.expect(maxInt(u32) == 4294967295);
- testing.expect(maxInt(u64) == 18446744073709551615);
- testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
-
- testing.expect(maxInt(i0) == 0);
- testing.expect(maxInt(i1) == 0);
- testing.expect(maxInt(i8) == 127);
- testing.expect(maxInt(i16) == 32767);
- testing.expect(maxInt(i32) == 2147483647);
- testing.expect(maxInt(i63) == 4611686018427387903);
- testing.expect(maxInt(i64) == 9223372036854775807);
- testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
-
- testing.expect(minInt(u0) == 0);
- testing.expect(minInt(u1) == 0);
- testing.expect(minInt(u8) == 0);
- testing.expect(minInt(u16) == 0);
- testing.expect(minInt(u32) == 0);
- testing.expect(minInt(u63) == 0);
- testing.expect(minInt(u64) == 0);
- testing.expect(minInt(u128) == 0);
-
- testing.expect(minInt(i0) == 0);
- testing.expect(minInt(i1) == -1);
- testing.expect(minInt(i8) == -128);
- testing.expect(minInt(i16) == -32768);
- testing.expect(minInt(i32) == -2147483648);
- testing.expect(minInt(i63) == -4611686018427387904);
- testing.expect(minInt(i64) == -9223372036854775808);
- testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
-}
-
-test "max value type" {
- // If the type of maxInt(i32) was i32 then this implicit cast to
- // u32 would not work. But since the value is a number literal,
- // it works fine.
- const x: u32 = maxInt(i32);
- testing.expect(x == 2147483647);
-}
diff --git a/std/math/inf.zig b/std/math/inf.zig
index fb7a3489c5bad18a84da9cd2f0517e8a41d1ea5b..e1bfbb197ac9f8461fb233d0fdac761c2fe6602d 100644
--- a/std/math/inf.zig
+++ b/std/math/inf.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
pub fn inf(comptime T: type) T {
diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig
index bf1c9ac63c5bb795d93e0bce2becf36fc5f3f18d..ee8a5ff59072a6eb29cb40101d89545d89cac29f 100644
--- a/std/math/isfinite.zig
+++ b/std/math/isfinite.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/isinf.zig b/std/math/isinf.zig
index b1e3f7795eb81e328954ae227878dfac8d6bcf7b..1b1759bd36d2556c3275f049290eed87ceb53a8f 100644
--- a/std/math/isinf.zig
+++ b/std/math/isinf.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/isnan.zig b/std/math/isnan.zig
index e8b03a1e346d06e06b981863d0e8bd63130464fb..7645528ea9d5506be81712352c15de2009f873cd 100644
--- a/std/math/isnan.zig
+++ b/std/math/isnan.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig
index 2c57aea7a9af84b3e65d838a8ce228d7862b6b05..cddcada1d3acfa5e5e661e57e0490f6b081dfa75 100644
--- a/std/math/isnormal.zig
+++ b/std/math/isnormal.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/ln.zig b/std/math/ln.zig
index 257ce8054ffcd9ee6d6b7b78749a224a6847da67..82b212f00f9c5477e57f62a82f30d51976dcc44a 100644
--- a/std/math/ln.zig
+++ b/std/math/ln.zig
@@ -5,7 +5,7 @@
// - ln(x) = nan if x < 0
// - ln(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const builtin = @import("builtin");
diff --git a/std/math/log.zig b/std/math/log.zig
index 21cffcc07884bd5cd046a42f8fb4aa186b0d15bf..100dc2fb7f9867a002d5bcf0bb8f95e845ab60f9 100644
--- a/std/math/log.zig
+++ b/std/math/log.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
diff --git a/std/math/log10.zig b/std/math/log10.zig
index 8055f712801aba0fa6829d22804271b95d1aa624..7311778dddc71ef593547d6a56308340d40082c6 100644
--- a/std/math/log10.zig
+++ b/std/math/log10.zig
@@ -5,7 +5,7 @@
// - log10(x) = nan if x < 0
// - log10(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const testing = std.testing;
const builtin = @import("builtin");
diff --git a/std/math/log1p.zig b/std/math/log1p.zig
index 257e7b90d458cd770b48eef4d3d081cdbde22ed1..c9be1132be92fddf9afb514c00d83675c0006c68 100644
--- a/std/math/log1p.zig
+++ b/std/math/log1p.zig
@@ -7,7 +7,7 @@
// - log1p(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/log2.zig b/std/math/log2.zig
index 1bb51bf9f9c0c5f8ac5b9b5d77cd149b4223baf6..e2dbf4105a9b074bd75fc5ddc98629adb7867d67 100644
--- a/std/math/log2.zig
+++ b/std/math/log2.zig
@@ -5,7 +5,7 @@
// - log2(x) = nan if x < 0
// - log2(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const builtin = @import("builtin");
diff --git a/std/math/modf.zig b/std/math/modf.zig
index 2dadda76a91355caab53686372732dd5a20af952..e5a4964e63901dc3f126d94c4305326482fc95f2 100644
--- a/std/math/modf.zig
+++ b/std/math/modf.zig
@@ -3,7 +3,7 @@
// - modf(+-inf) = +-inf, nan
// - modf(nan) = nan, nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/math/nan.zig b/std/math/nan.zig
index d3ad43da2371930e9504e1189ad01c780b147d5c..1a11a141d5ae7007c7e00de04c069db34021e36b 100644
--- a/std/math/nan.zig
+++ b/std/math/nan.zig
@@ -1,4 +1,4 @@
-const math = @import("index.zig");
+const math = @import("../math.zig");
pub fn nan(comptime T: type) T {
return switch (T) {
diff --git a/std/math/pow.zig b/std/math/pow.zig
index f037f66d7e0491fc7fa882d35865e5652e1d1473..81bb2d95d5ab009f42d5184c3719951ae1b2f31b 100644
--- a/std/math/pow.zig
+++ b/std/math/pow.zig
@@ -22,7 +22,7 @@
// pow(x, y) = nan for finite x < 0 and finite non-integer y
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/powi.zig b/std/math/powi.zig
index dffb564da76db1b7c0d4a09da3c88b490b41d1e6..b7212efcbf7e98e9e7942defe288dcec61f9052c 100644
--- a/std/math/powi.zig
+++ b/std/math/powi.zig
@@ -9,7 +9,7 @@
// powi(x, y) = Underflow for for y > @sizeOf(x) - 1 y < 0
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/math/round.zig b/std/math/round.zig
index 7346b703c9c54422b19d57f65111136f1e207542..39ff56ca79cee60aa5559e567a601d5605887a24 100644
--- a/std/math/round.zig
+++ b/std/math/round.zig
@@ -6,7 +6,7 @@
const builtin = @import("builtin");
const expect = std.testing.expect;
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
pub fn round(x: var) @typeOf(x) {
diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig
index d37a8659a945849d014a4cd6e79d39a14b508e6c..d1338f5acb719bec08df3a156957243bfdb72cc7 100644
--- a/std/math/scalbn.zig
+++ b/std/math/scalbn.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/signbit.zig b/std/math/signbit.zig
index 728f651aece35456ae9ba7fa11a612cd1c2f33f7..9727152b07947170033e19c58ac465da94d2dd88 100644
--- a/std/math/signbit.zig
+++ b/std/math/signbit.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/sin.zig b/std/math/sin.zig
index 5ade6636c73a81fda1f973bfa84e27c398f4bf5f..e25b8a292b66a674df9e69c0842dcaf82980e65f 100644
--- a/std/math/sin.zig
+++ b/std/math/sin.zig
@@ -5,7 +5,7 @@
// - sin(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/sinh.zig b/std/math/sinh.zig
index 95924ba55a8ca473c1883c82845f3b2b02c21a80..cf4363c4a9e3a69a4433b9e056c9e1617a60ddf3 100644
--- a/std/math/sinh.zig
+++ b/std/math/sinh.zig
@@ -5,7 +5,7 @@
// - sinh(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const expo2 = @import("expo2.zig").expo2;
diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig
index 9996b44b20c83f6f057066fc8a77ad07ac29e561..9062f598a1c7e554b47d2dcb00c99ec59f0a291d 100644
--- a/std/math/sqrt.zig
+++ b/std/math/sqrt.zig
@@ -5,7 +5,7 @@
// - sqrt(x) = nan if x < 0
// - sqrt(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const builtin = @import("builtin");
diff --git a/std/math/tan.zig b/std/math/tan.zig
index ec4309232082cd76f56fe9220838f16548618ee6..fc11ebdef791443473f2122575e983b26747a667 100644
--- a/std/math/tan.zig
+++ b/std/math/tan.zig
@@ -5,7 +5,7 @@
// - tan(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
diff --git a/std/math/tanh.zig b/std/math/tanh.zig
index a35449a0536aa58888c0b7e0b2eaa86f8be42909..f88ecfdc9c22e7fc696b870f58b6b2f0a10e5cc5 100644
--- a/std/math/tanh.zig
+++ b/std/math/tanh.zig
@@ -5,7 +5,7 @@
// - sinh(nan) = nan
const builtin = @import("builtin");
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const expo2 = @import("expo2.zig").expo2;
diff --git a/std/math/trunc.zig b/std/math/trunc.zig
index 8c91ccc568d1b5c9ab8a5561efbc31f4430be960..9449d0e7ebb5737657ebf9e21414fa1aa3d79003 100644
--- a/std/math/trunc.zig
+++ b/std/math/trunc.zig
@@ -4,7 +4,7 @@
// - trunc(+-inf) = +-inf
// - trunc(nan) = nan
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
diff --git a/std/mem.zig b/std/mem.zig
index 39b9701754a90be90259961a2e47635e05c0401c..681054d0874c2d1d65e9e7f77a7e024ae03da2cc 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const debug = std.debug;
const assert = debug.assert;
const math = std.math;
diff --git a/std/meta.zig b/std/meta.zig
new file mode 100644
index 0000000000000000000000000000000000000000..215c5dfad859c83005957cbc50a8bceeb739d1ad
--- /dev/null
+++ b/std/meta.zig
@@ -0,0 +1,569 @@
+const std = @import("std.zig");
+const builtin = @import("builtin");
+const debug = std.debug;
+const mem = std.mem;
+const math = std.math;
+const testing = std.testing;
+
+pub const trait = @import("meta/trait.zig");
+
+const TypeId = builtin.TypeId;
+const TypeInfo = builtin.TypeInfo;
+
+pub fn tagName(v: var) []const u8 {
+ const T = @typeOf(v);
+ switch (@typeInfo(T)) {
+ TypeId.Enum => |info| {
+ const Tag = info.tag_type;
+ inline for (info.fields) |field| {
+ if (field.value == @enumToInt(v)) return field.name;
+ }
+
+ unreachable;
+ },
+ TypeId.Union => |info| {
+ const UnionTag = if (info.tag_type) |UT| UT else @compileError("union is untagged");
+ const Tag = @typeInfo(UnionTag).Enum.tag_type;
+ inline for (info.fields) |field| {
+ if (field.enum_field.?.value == @enumToInt(UnionTag(v)))
+ return field.name;
+ }
+
+ unreachable;
+ },
+ TypeId.ErrorSet => |info| {
+ inline for (info.errors) |err| {
+ if (err.value == @errorToInt(v)) return err.name;
+ }
+
+ unreachable;
+ },
+ else => @compileError("expected enum, error set or union type, found '" ++ @typeName(T) ++ "'"),
+ }
+}
+
+test "std.meta.tagName" {
+ const E1 = enum {
+ A,
+ B,
+ };
+ const E2 = enum(u8) {
+ C = 33,
+ D,
+ };
+ const U1 = union(enum) {
+ G: u8,
+ H: u16,
+ };
+ const U2 = union(E2) {
+ C: u8,
+ D: u16,
+ };
+
+ var u1g = U1{ .G = 0 };
+ var u1h = U1{ .H = 0 };
+ var u2a = U2{ .C = 0 };
+ var u2b = U2{ .D = 0 };
+
+ testing.expect(mem.eql(u8, tagName(E1.A), "A"));
+ testing.expect(mem.eql(u8, tagName(E1.B), "B"));
+ testing.expect(mem.eql(u8, tagName(E2.C), "C"));
+ testing.expect(mem.eql(u8, tagName(E2.D), "D"));
+ testing.expect(mem.eql(u8, tagName(error.E), "E"));
+ testing.expect(mem.eql(u8, tagName(error.F), "F"));
+ testing.expect(mem.eql(u8, tagName(u1g), "G"));
+ testing.expect(mem.eql(u8, tagName(u1h), "H"));
+ testing.expect(mem.eql(u8, tagName(u2a), "C"));
+ testing.expect(mem.eql(u8, tagName(u2b), "D"));
+}
+
+pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
+ inline for (@typeInfo(T).Enum.fields) |enumField| {
+ if (std.mem.eql(u8, str, enumField.name)) {
+ return @field(T, enumField.name);
+ }
+ }
+ return null;
+}
+
+test "std.meta.stringToEnum" {
+ const E1 = enum {
+ A,
+ B,
+ };
+ testing.expect(E1.A == stringToEnum(E1, "A").?);
+ testing.expect(E1.B == stringToEnum(E1, "B").?);
+ testing.expect(null == stringToEnum(E1, "C"));
+}
+
+pub fn bitCount(comptime T: type) comptime_int {
+ return switch (@typeInfo(T)) {
+ TypeId.Int => |info| info.bits,
+ TypeId.Float => |info| info.bits,
+ else => @compileError("Expected int or float type, found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.bitCount" {
+ testing.expect(bitCount(u8) == 8);
+ testing.expect(bitCount(f32) == 32);
+}
+
+pub fn alignment(comptime T: type) comptime_int {
+ //@alignOf works on non-pointer types
+ const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
+ return @typeInfo(P).Pointer.alignment;
+}
+
+test "std.meta.alignment" {
+ testing.expect(alignment(u8) == 1);
+ testing.expect(alignment(*align(1) u8) == 1);
+ testing.expect(alignment(*align(2) u8) == 2);
+ testing.expect(alignment([]align(1) u8) == 1);
+ testing.expect(alignment([]align(2) u8) == 2);
+}
+
+pub fn Child(comptime T: type) type {
+ return switch (@typeInfo(T)) {
+ TypeId.Array => |info| info.child,
+ TypeId.Pointer => |info| info.child,
+ TypeId.Optional => |info| info.child,
+ TypeId.Promise => |info| if (info.child) |child| child else null,
+ else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.Child" {
+ testing.expect(Child([1]u8) == u8);
+ testing.expect(Child(*u8) == u8);
+ testing.expect(Child([]u8) == u8);
+ testing.expect(Child(?u8) == u8);
+ testing.expect(Child(promise->u8) == u8);
+}
+
+pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
+ return switch (@typeInfo(T)) {
+ TypeId.Struct => |info| info.layout,
+ TypeId.Enum => |info| info.layout,
+ TypeId.Union => |info| info.layout,
+ else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.containerLayout" {
+ const E1 = enum {
+ A,
+ };
+ const E2 = packed enum {
+ A,
+ };
+ const E3 = extern enum {
+ A,
+ };
+ const S1 = struct {};
+ const S2 = packed struct {};
+ const S3 = extern struct {};
+ const U1 = union {
+ a: u8,
+ };
+ const U2 = packed union {
+ a: u8,
+ };
+ const U3 = extern union {
+ a: u8,
+ };
+
+ testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto);
+ testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed);
+ testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern);
+ testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto);
+ testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed);
+ testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern);
+ testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto);
+ testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed);
+ testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern);
+}
+
+pub fn definitions(comptime T: type) []TypeInfo.Definition {
+ return switch (@typeInfo(T)) {
+ TypeId.Struct => |info| info.defs,
+ TypeId.Enum => |info| info.defs,
+ TypeId.Union => |info| info.defs,
+ else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.definitions" {
+ const E1 = enum {
+ A,
+
+ fn a() void {}
+ };
+ const S1 = struct {
+ fn a() void {}
+ };
+ const U1 = union {
+ a: u8,
+
+ fn a() void {}
+ };
+
+ const defs = comptime [][]TypeInfo.Definition{
+ definitions(E1),
+ definitions(S1),
+ definitions(U1),
+ };
+
+ inline for (defs) |def| {
+ testing.expect(def.len == 1);
+ testing.expect(comptime mem.eql(u8, def[0].name, "a"));
+ }
+}
+
+pub fn definitionInfo(comptime T: type, comptime def_name: []const u8) TypeInfo.Definition {
+ inline for (comptime definitions(T)) |def| {
+ if (comptime mem.eql(u8, def.name, def_name))
+ return def;
+ }
+
+ @compileError("'" ++ @typeName(T) ++ "' has no definition '" ++ def_name ++ "'");
+}
+
+test "std.meta.definitionInfo" {
+ const E1 = enum {
+ A,
+
+ fn a() void {}
+ };
+ const S1 = struct {
+ fn a() void {}
+ };
+ const U1 = union {
+ a: u8,
+
+ fn a() void {}
+ };
+
+ const infos = comptime []TypeInfo.Definition{
+ definitionInfo(E1, "a"),
+ definitionInfo(S1, "a"),
+ definitionInfo(U1, "a"),
+ };
+
+ inline for (infos) |info| {
+ testing.expect(comptime mem.eql(u8, info.name, "a"));
+ testing.expect(!info.is_pub);
+ }
+}
+
+pub fn fields(comptime T: type) switch (@typeInfo(T)) {
+ TypeId.Struct => []TypeInfo.StructField,
+ TypeId.Union => []TypeInfo.UnionField,
+ TypeId.ErrorSet => []TypeInfo.Error,
+ TypeId.Enum => []TypeInfo.EnumField,
+ else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
+} {
+ return switch (@typeInfo(T)) {
+ TypeId.Struct => |info| info.fields,
+ TypeId.Union => |info| info.fields,
+ TypeId.Enum => |info| info.fields,
+ TypeId.ErrorSet => |info| info.errors,
+ else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.fields" {
+ const E1 = enum {
+ A,
+ };
+ const E2 = error{A};
+ const S1 = struct {
+ a: u8,
+ };
+ const U1 = union {
+ a: u8,
+ };
+
+ const e1f = comptime fields(E1);
+ const e2f = comptime fields(E2);
+ const sf = comptime fields(S1);
+ const uf = comptime fields(U1);
+
+ testing.expect(e1f.len == 1);
+ testing.expect(e2f.len == 1);
+ testing.expect(sf.len == 1);
+ testing.expect(uf.len == 1);
+ testing.expect(mem.eql(u8, e1f[0].name, "A"));
+ testing.expect(mem.eql(u8, e2f[0].name, "A"));
+ testing.expect(mem.eql(u8, sf[0].name, "a"));
+ testing.expect(mem.eql(u8, uf[0].name, "a"));
+ testing.expect(comptime sf[0].field_type == u8);
+ testing.expect(comptime uf[0].field_type == u8);
+}
+
+pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) {
+ TypeId.Struct => TypeInfo.StructField,
+ TypeId.Union => TypeInfo.UnionField,
+ TypeId.ErrorSet => TypeInfo.Error,
+ TypeId.Enum => TypeInfo.EnumField,
+ else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
+} {
+ inline for (comptime fields(T)) |field| {
+ if (comptime mem.eql(u8, field.name, field_name))
+ return field;
+ }
+
+ @compileError("'" ++ @typeName(T) ++ "' has no field '" ++ field_name ++ "'");
+}
+
+test "std.meta.fieldInfo" {
+ const E1 = enum {
+ A,
+ };
+ const E2 = error{A};
+ const S1 = struct {
+ a: u8,
+ };
+ const U1 = union {
+ a: u8,
+ };
+
+ const e1f = comptime fieldInfo(E1, "A");
+ const e2f = comptime fieldInfo(E2, "A");
+ const sf = comptime fieldInfo(S1, "a");
+ const uf = comptime fieldInfo(U1, "a");
+
+ testing.expect(mem.eql(u8, e1f.name, "A"));
+ testing.expect(mem.eql(u8, e2f.name, "A"));
+ testing.expect(mem.eql(u8, sf.name, "a"));
+ testing.expect(mem.eql(u8, uf.name, "a"));
+ testing.expect(comptime sf.field_type == u8);
+ testing.expect(comptime uf.field_type == u8);
+}
+
+pub fn TagType(comptime T: type) type {
+ return switch (@typeInfo(T)) {
+ TypeId.Enum => |info| info.tag_type,
+ TypeId.Union => |info| if (info.tag_type) |Tag| Tag else null,
+ else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
+ };
+}
+
+test "std.meta.TagType" {
+ const E = enum(u8) {
+ C = 33,
+ D,
+ };
+ const U = union(E) {
+ C: u8,
+ D: u16,
+ };
+
+ testing.expect(TagType(E) == u8);
+ testing.expect(TagType(U) == E);
+}
+
+///Returns the active tag of a tagged union
+pub fn activeTag(u: var) @TagType(@typeOf(u)) {
+ const T = @typeOf(u);
+ return @TagType(T)(u);
+}
+
+test "std.meta.activeTag" {
+ const UE = enum {
+ Int,
+ Float,
+ };
+
+ const U = union(UE) {
+ Int: u32,
+ Float: f32,
+ };
+
+ var u = U{ .Int = 32 };
+ testing.expect(activeTag(u) == UE.Int);
+
+ u = U{ .Float = 112.9876 };
+ testing.expect(activeTag(u) == UE.Float);
+}
+
+///Given a tagged union type, and an enum, return the type of the union
+/// field corresponding to the enum tag.
+pub fn TagPayloadType(comptime U: type, tag: var) type {
+ const Tag = @typeOf(tag);
+ testing.expect(trait.is(builtin.TypeId.Union)(U));
+ testing.expect(trait.is(builtin.TypeId.Enum)(Tag));
+
+ const info = @typeInfo(U).Union;
+
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
+ }
+ unreachable;
+}
+
+test "std.meta.TagPayloadType" {
+ const Event = union(enum) {
+ Moved: struct {
+ from: i32,
+ to: i32,
+ },
+ };
+ const MovedEvent = TagPayloadType(Event, Event.Moved);
+ var e: Event = undefined;
+ testing.expect(MovedEvent == @typeOf(e.Moved));
+}
+
+///Compares two of any type for equality. Containers are compared on a field-by-field basis,
+/// where possible. Pointers are not followed.
+pub fn eql(a: var, b: @typeOf(a)) bool {
+ const T = @typeOf(a);
+
+ switch (@typeId(T)) {
+ builtin.TypeId.Struct => {
+ const info = @typeInfo(T).Struct;
+
+ inline for (info.fields) |field_info| {
+ if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
+ }
+ return true;
+ },
+ builtin.TypeId.ErrorUnion => {
+ if (a) |a_p| {
+ if (b) |b_p| return eql(a_p, b_p) else |_| return false;
+ } else |a_e| {
+ if (b) |_| return false else |b_e| return a_e == b_e;
+ }
+ },
+ builtin.TypeId.Union => {
+ const info = @typeInfo(T).Union;
+
+ if (info.tag_type) |_| {
+ const tag_a = activeTag(a);
+ const tag_b = activeTag(b);
+ if (tag_a != tag_b) return false;
+
+ inline for (info.fields) |field_info| {
+ const enum_field = field_info.enum_field.?;
+ if (enum_field.value == @enumToInt(tag_a)) {
+ return eql(@field(a, enum_field.name), @field(b, enum_field.name));
+ }
+ }
+ return false;
+ }
+
+ @compileError("cannot compare untagged union type " ++ @typeName(T));
+ },
+ builtin.TypeId.Array => {
+ if (a.len != b.len) return false;
+ for (a) |e, i|
+ if (!eql(e, b[i])) return false;
+ return true;
+ },
+ builtin.TypeId.Pointer => {
+ const info = @typeInfo(T).Pointer;
+ switch (info.size) {
+ builtin.TypeInfo.Pointer.Size.One,
+ builtin.TypeInfo.Pointer.Size.Many,
+ builtin.TypeInfo.Pointer.Size.C,
+ => return a == b,
+ builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
+ }
+ },
+ builtin.TypeId.Optional => {
+ if (a == null and b == null) return true;
+ if (a == null or b == null) return false;
+ return eql(a.?, b.?);
+ },
+ else => return a == b,
+ }
+}
+
+test "std.meta.eql" {
+ const S = struct {
+ a: u32,
+ b: f64,
+ c: [5]u8,
+ };
+
+ const U = union(enum) {
+ s: S,
+ f: ?f32,
+ };
+
+ const s_1 = S{
+ .a = 134,
+ .b = 123.3,
+ .c = "12345",
+ };
+
+ const s_2 = S{
+ .a = 1,
+ .b = 123.3,
+ .c = "54321",
+ };
+
+ const s_3 = S{
+ .a = 134,
+ .b = 123.3,
+ .c = "12345",
+ };
+
+ const u_1 = U{ .f = 24 };
+ const u_2 = U{ .s = s_1 };
+ const u_3 = U{ .f = 24 };
+
+ testing.expect(eql(s_1, s_3));
+ testing.expect(eql(&s_1, &s_1));
+ testing.expect(!eql(&s_1, &s_3));
+ testing.expect(eql(u_1, u_3));
+ testing.expect(!eql(u_1, u_2));
+
+ var a1 = "abcdef";
+ var a2 = "abcdef";
+ var a3 = "ghijkl";
+
+ testing.expect(eql(a1, a2));
+ testing.expect(!eql(a1, a3));
+ testing.expect(!eql(a1[0..], a2[0..]));
+
+ const EU = struct {
+ fn tst(err: bool) !u8 {
+ if (err) return error.Error;
+ return u8(5);
+ }
+ };
+
+ testing.expect(eql(EU.tst(true), EU.tst(true)));
+ testing.expect(eql(EU.tst(false), EU.tst(false)));
+ testing.expect(!eql(EU.tst(false), EU.tst(true)));
+}
+
+test "intToEnum with error return" {
+ const E1 = enum {
+ A,
+ };
+ const E2 = enum {
+ A,
+ B,
+ };
+
+ var zero: u8 = 0;
+ var one: u16 = 1;
+ testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
+ testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
+ testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
+}
+
+pub const IntToEnumError = error{InvalidEnumTag};
+
+pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
+ comptime var i = 0;
+ inline while (i != @memberCount(Tag)) : (i += 1) {
+ const this_tag_value = @field(Tag, @memberName(Tag, i));
+ if (tag_int == @enumToInt(this_tag_value)) {
+ return this_tag_value;
+ }
+ }
+ return error.InvalidEnumTag;
+}
diff --git a/std/meta/index.zig b/std/meta/index.zig
deleted file mode 100644
index 652e2d39ec1137b1c9cc34b92aa819730a25d818..0000000000000000000000000000000000000000
--- a/std/meta/index.zig
+++ /dev/null
@@ -1,569 +0,0 @@
-const std = @import("../index.zig");
-const builtin = @import("builtin");
-const debug = std.debug;
-const mem = std.mem;
-const math = std.math;
-const testing = std.testing;
-
-pub const trait = @import("trait.zig");
-
-const TypeId = builtin.TypeId;
-const TypeInfo = builtin.TypeInfo;
-
-pub fn tagName(v: var) []const u8 {
- const T = @typeOf(v);
- switch (@typeInfo(T)) {
- TypeId.Enum => |info| {
- const Tag = info.tag_type;
- inline for (info.fields) |field| {
- if (field.value == @enumToInt(v)) return field.name;
- }
-
- unreachable;
- },
- TypeId.Union => |info| {
- const UnionTag = if (info.tag_type) |UT| UT else @compileError("union is untagged");
- const Tag = @typeInfo(UnionTag).Enum.tag_type;
- inline for (info.fields) |field| {
- if (field.enum_field.?.value == @enumToInt(UnionTag(v)))
- return field.name;
- }
-
- unreachable;
- },
- TypeId.ErrorSet => |info| {
- inline for (info.errors) |err| {
- if (err.value == @errorToInt(v)) return err.name;
- }
-
- unreachable;
- },
- else => @compileError("expected enum, error set or union type, found '" ++ @typeName(T) ++ "'"),
- }
-}
-
-test "std.meta.tagName" {
- const E1 = enum {
- A,
- B,
- };
- const E2 = enum(u8) {
- C = 33,
- D,
- };
- const U1 = union(enum) {
- G: u8,
- H: u16,
- };
- const U2 = union(E2) {
- C: u8,
- D: u16,
- };
-
- var u1g = U1{ .G = 0 };
- var u1h = U1{ .H = 0 };
- var u2a = U2{ .C = 0 };
- var u2b = U2{ .D = 0 };
-
- testing.expect(mem.eql(u8, tagName(E1.A), "A"));
- testing.expect(mem.eql(u8, tagName(E1.B), "B"));
- testing.expect(mem.eql(u8, tagName(E2.C), "C"));
- testing.expect(mem.eql(u8, tagName(E2.D), "D"));
- testing.expect(mem.eql(u8, tagName(error.E), "E"));
- testing.expect(mem.eql(u8, tagName(error.F), "F"));
- testing.expect(mem.eql(u8, tagName(u1g), "G"));
- testing.expect(mem.eql(u8, tagName(u1h), "H"));
- testing.expect(mem.eql(u8, tagName(u2a), "C"));
- testing.expect(mem.eql(u8, tagName(u2b), "D"));
-}
-
-pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
- inline for (@typeInfo(T).Enum.fields) |enumField| {
- if (std.mem.eql(u8, str, enumField.name)) {
- return @field(T, enumField.name);
- }
- }
- return null;
-}
-
-test "std.meta.stringToEnum" {
- const E1 = enum {
- A,
- B,
- };
- testing.expect(E1.A == stringToEnum(E1, "A").?);
- testing.expect(E1.B == stringToEnum(E1, "B").?);
- testing.expect(null == stringToEnum(E1, "C"));
-}
-
-pub fn bitCount(comptime T: type) comptime_int {
- return switch (@typeInfo(T)) {
- TypeId.Int => |info| info.bits,
- TypeId.Float => |info| info.bits,
- else => @compileError("Expected int or float type, found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.bitCount" {
- testing.expect(bitCount(u8) == 8);
- testing.expect(bitCount(f32) == 32);
-}
-
-pub fn alignment(comptime T: type) comptime_int {
- //@alignOf works on non-pointer types
- const P = if (comptime trait.is(TypeId.Pointer)(T)) T else *T;
- return @typeInfo(P).Pointer.alignment;
-}
-
-test "std.meta.alignment" {
- testing.expect(alignment(u8) == 1);
- testing.expect(alignment(*align(1) u8) == 1);
- testing.expect(alignment(*align(2) u8) == 2);
- testing.expect(alignment([]align(1) u8) == 1);
- testing.expect(alignment([]align(2) u8) == 2);
-}
-
-pub fn Child(comptime T: type) type {
- return switch (@typeInfo(T)) {
- TypeId.Array => |info| info.child,
- TypeId.Pointer => |info| info.child,
- TypeId.Optional => |info| info.child,
- TypeId.Promise => |info| if (info.child) |child| child else null,
- else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.Child" {
- testing.expect(Child([1]u8) == u8);
- testing.expect(Child(*u8) == u8);
- testing.expect(Child([]u8) == u8);
- testing.expect(Child(?u8) == u8);
- testing.expect(Child(promise->u8) == u8);
-}
-
-pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
- return switch (@typeInfo(T)) {
- TypeId.Struct => |info| info.layout,
- TypeId.Enum => |info| info.layout,
- TypeId.Union => |info| info.layout,
- else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.containerLayout" {
- const E1 = enum {
- A,
- };
- const E2 = packed enum {
- A,
- };
- const E3 = extern enum {
- A,
- };
- const S1 = struct {};
- const S2 = packed struct {};
- const S3 = extern struct {};
- const U1 = union {
- a: u8,
- };
- const U2 = packed union {
- a: u8,
- };
- const U3 = extern union {
- a: u8,
- };
-
- testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto);
- testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed);
- testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern);
- testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto);
- testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed);
- testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern);
- testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto);
- testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed);
- testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern);
-}
-
-pub fn definitions(comptime T: type) []TypeInfo.Definition {
- return switch (@typeInfo(T)) {
- TypeId.Struct => |info| info.defs,
- TypeId.Enum => |info| info.defs,
- TypeId.Union => |info| info.defs,
- else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.definitions" {
- const E1 = enum {
- A,
-
- fn a() void {}
- };
- const S1 = struct {
- fn a() void {}
- };
- const U1 = union {
- a: u8,
-
- fn a() void {}
- };
-
- const defs = comptime [][]TypeInfo.Definition{
- definitions(E1),
- definitions(S1),
- definitions(U1),
- };
-
- inline for (defs) |def| {
- testing.expect(def.len == 1);
- testing.expect(comptime mem.eql(u8, def[0].name, "a"));
- }
-}
-
-pub fn definitionInfo(comptime T: type, comptime def_name: []const u8) TypeInfo.Definition {
- inline for (comptime definitions(T)) |def| {
- if (comptime mem.eql(u8, def.name, def_name))
- return def;
- }
-
- @compileError("'" ++ @typeName(T) ++ "' has no definition '" ++ def_name ++ "'");
-}
-
-test "std.meta.definitionInfo" {
- const E1 = enum {
- A,
-
- fn a() void {}
- };
- const S1 = struct {
- fn a() void {}
- };
- const U1 = union {
- a: u8,
-
- fn a() void {}
- };
-
- const infos = comptime []TypeInfo.Definition{
- definitionInfo(E1, "a"),
- definitionInfo(S1, "a"),
- definitionInfo(U1, "a"),
- };
-
- inline for (infos) |info| {
- testing.expect(comptime mem.eql(u8, info.name, "a"));
- testing.expect(!info.is_pub);
- }
-}
-
-pub fn fields(comptime T: type) switch (@typeInfo(T)) {
- TypeId.Struct => []TypeInfo.StructField,
- TypeId.Union => []TypeInfo.UnionField,
- TypeId.ErrorSet => []TypeInfo.Error,
- TypeId.Enum => []TypeInfo.EnumField,
- else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
-} {
- return switch (@typeInfo(T)) {
- TypeId.Struct => |info| info.fields,
- TypeId.Union => |info| info.fields,
- TypeId.Enum => |info| info.fields,
- TypeId.ErrorSet => |info| info.errors,
- else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.fields" {
- const E1 = enum {
- A,
- };
- const E2 = error{A};
- const S1 = struct {
- a: u8,
- };
- const U1 = union {
- a: u8,
- };
-
- const e1f = comptime fields(E1);
- const e2f = comptime fields(E2);
- const sf = comptime fields(S1);
- const uf = comptime fields(U1);
-
- testing.expect(e1f.len == 1);
- testing.expect(e2f.len == 1);
- testing.expect(sf.len == 1);
- testing.expect(uf.len == 1);
- testing.expect(mem.eql(u8, e1f[0].name, "A"));
- testing.expect(mem.eql(u8, e2f[0].name, "A"));
- testing.expect(mem.eql(u8, sf[0].name, "a"));
- testing.expect(mem.eql(u8, uf[0].name, "a"));
- testing.expect(comptime sf[0].field_type == u8);
- testing.expect(comptime uf[0].field_type == u8);
-}
-
-pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) {
- TypeId.Struct => TypeInfo.StructField,
- TypeId.Union => TypeInfo.UnionField,
- TypeId.ErrorSet => TypeInfo.Error,
- TypeId.Enum => TypeInfo.EnumField,
- else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
-} {
- inline for (comptime fields(T)) |field| {
- if (comptime mem.eql(u8, field.name, field_name))
- return field;
- }
-
- @compileError("'" ++ @typeName(T) ++ "' has no field '" ++ field_name ++ "'");
-}
-
-test "std.meta.fieldInfo" {
- const E1 = enum {
- A,
- };
- const E2 = error{A};
- const S1 = struct {
- a: u8,
- };
- const U1 = union {
- a: u8,
- };
-
- const e1f = comptime fieldInfo(E1, "A");
- const e2f = comptime fieldInfo(E2, "A");
- const sf = comptime fieldInfo(S1, "a");
- const uf = comptime fieldInfo(U1, "a");
-
- testing.expect(mem.eql(u8, e1f.name, "A"));
- testing.expect(mem.eql(u8, e2f.name, "A"));
- testing.expect(mem.eql(u8, sf.name, "a"));
- testing.expect(mem.eql(u8, uf.name, "a"));
- testing.expect(comptime sf.field_type == u8);
- testing.expect(comptime uf.field_type == u8);
-}
-
-pub fn TagType(comptime T: type) type {
- return switch (@typeInfo(T)) {
- TypeId.Enum => |info| info.tag_type,
- TypeId.Union => |info| if (info.tag_type) |Tag| Tag else null,
- else => @compileError("expected enum or union type, found '" ++ @typeName(T) ++ "'"),
- };
-}
-
-test "std.meta.TagType" {
- const E = enum(u8) {
- C = 33,
- D,
- };
- const U = union(E) {
- C: u8,
- D: u16,
- };
-
- testing.expect(TagType(E) == u8);
- testing.expect(TagType(U) == E);
-}
-
-///Returns the active tag of a tagged union
-pub fn activeTag(u: var) @TagType(@typeOf(u)) {
- const T = @typeOf(u);
- return @TagType(T)(u);
-}
-
-test "std.meta.activeTag" {
- const UE = enum {
- Int,
- Float,
- };
-
- const U = union(UE) {
- Int: u32,
- Float: f32,
- };
-
- var u = U{ .Int = 32 };
- testing.expect(activeTag(u) == UE.Int);
-
- u = U{ .Float = 112.9876 };
- testing.expect(activeTag(u) == UE.Float);
-}
-
-///Given a tagged union type, and an enum, return the type of the union
-/// field corresponding to the enum tag.
-pub fn TagPayloadType(comptime U: type, tag: var) type {
- const Tag = @typeOf(tag);
- testing.expect(trait.is(builtin.TypeId.Union)(U));
- testing.expect(trait.is(builtin.TypeId.Enum)(Tag));
-
- const info = @typeInfo(U).Union;
-
- inline for (info.fields) |field_info| {
- if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
- }
- unreachable;
-}
-
-test "std.meta.TagPayloadType" {
- const Event = union(enum) {
- Moved: struct {
- from: i32,
- to: i32,
- },
- };
- const MovedEvent = TagPayloadType(Event, Event.Moved);
- var e: Event = undefined;
- testing.expect(MovedEvent == @typeOf(e.Moved));
-}
-
-///Compares two of any type for equality. Containers are compared on a field-by-field basis,
-/// where possible. Pointers are not followed.
-pub fn eql(a: var, b: @typeOf(a)) bool {
- const T = @typeOf(a);
-
- switch (@typeId(T)) {
- builtin.TypeId.Struct => {
- const info = @typeInfo(T).Struct;
-
- inline for (info.fields) |field_info| {
- if (!eql(@field(a, field_info.name), @field(b, field_info.name))) return false;
- }
- return true;
- },
- builtin.TypeId.ErrorUnion => {
- if (a) |a_p| {
- if (b) |b_p| return eql(a_p, b_p) else |_| return false;
- } else |a_e| {
- if (b) |_| return false else |b_e| return a_e == b_e;
- }
- },
- builtin.TypeId.Union => {
- const info = @typeInfo(T).Union;
-
- if (info.tag_type) |_| {
- const tag_a = activeTag(a);
- const tag_b = activeTag(b);
- if (tag_a != tag_b) return false;
-
- inline for (info.fields) |field_info| {
- const enum_field = field_info.enum_field.?;
- if (enum_field.value == @enumToInt(tag_a)) {
- return eql(@field(a, enum_field.name), @field(b, enum_field.name));
- }
- }
- return false;
- }
-
- @compileError("cannot compare untagged union type " ++ @typeName(T));
- },
- builtin.TypeId.Array => {
- if (a.len != b.len) return false;
- for (a) |e, i|
- if (!eql(e, b[i])) return false;
- return true;
- },
- builtin.TypeId.Pointer => {
- const info = @typeInfo(T).Pointer;
- switch (info.size) {
- builtin.TypeInfo.Pointer.Size.One,
- builtin.TypeInfo.Pointer.Size.Many,
- builtin.TypeInfo.Pointer.Size.C,
- => return a == b,
- builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
- }
- },
- builtin.TypeId.Optional => {
- if (a == null and b == null) return true;
- if (a == null or b == null) return false;
- return eql(a.?, b.?);
- },
- else => return a == b,
- }
-}
-
-test "std.meta.eql" {
- const S = struct {
- a: u32,
- b: f64,
- c: [5]u8,
- };
-
- const U = union(enum) {
- s: S,
- f: ?f32,
- };
-
- const s_1 = S{
- .a = 134,
- .b = 123.3,
- .c = "12345",
- };
-
- const s_2 = S{
- .a = 1,
- .b = 123.3,
- .c = "54321",
- };
-
- const s_3 = S{
- .a = 134,
- .b = 123.3,
- .c = "12345",
- };
-
- const u_1 = U{ .f = 24 };
- const u_2 = U{ .s = s_1 };
- const u_3 = U{ .f = 24 };
-
- testing.expect(eql(s_1, s_3));
- testing.expect(eql(&s_1, &s_1));
- testing.expect(!eql(&s_1, &s_3));
- testing.expect(eql(u_1, u_3));
- testing.expect(!eql(u_1, u_2));
-
- var a1 = "abcdef";
- var a2 = "abcdef";
- var a3 = "ghijkl";
-
- testing.expect(eql(a1, a2));
- testing.expect(!eql(a1, a3));
- testing.expect(!eql(a1[0..], a2[0..]));
-
- const EU = struct {
- fn tst(err: bool) !u8 {
- if (err) return error.Error;
- return u8(5);
- }
- };
-
- testing.expect(eql(EU.tst(true), EU.tst(true)));
- testing.expect(eql(EU.tst(false), EU.tst(false)));
- testing.expect(!eql(EU.tst(false), EU.tst(true)));
-}
-
-test "intToEnum with error return" {
- const E1 = enum {
- A,
- };
- const E2 = enum {
- A,
- B,
- };
-
- var zero: u8 = 0;
- var one: u16 = 1;
- testing.expect(intToEnum(E1, zero) catch unreachable == E1.A);
- testing.expect(intToEnum(E2, one) catch unreachable == E2.B);
- testing.expectError(error.InvalidEnumTag, intToEnum(E1, one));
-}
-
-pub const IntToEnumError = error{InvalidEnumTag};
-
-pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
- comptime var i = 0;
- inline while (i != @memberCount(Tag)) : (i += 1) {
- const this_tag_value = @field(Tag, @memberName(Tag, i));
- if (tag_int == @enumToInt(this_tag_value)) {
- return this_tag_value;
- }
- }
- return error.InvalidEnumTag;
-}
diff --git a/std/meta/trait.zig b/std/meta/trait.zig
index 7fca5f4dcdb6ca349cf13f260e0772cc66aa09fa..f77619ec3931890a5947bd728542695d02a6d5b7 100644
--- a/std/meta/trait.zig
+++ b/std/meta/trait.zig
@@ -1,11 +1,11 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const mem = std.mem;
const debug = std.debug;
const testing = std.testing;
const warn = debug.warn;
-const meta = @import("index.zig");
+const meta = @import("../meta.zig");
//This is necessary if we want to return generic functions directly because of how the
// the type erasure works. see: #1375
diff --git a/std/mutex.zig b/std/mutex.zig
index a13b1c06c7b25dc5b38bb50dd0998444b0ea4a08..2b3ac4e366588ee88e3717984d3d069cc0d9ac1e 100644
--- a/std/mutex.zig
+++ b/std/mutex.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const AtomicOrder = builtin.AtomicOrder;
const AtomicRmwOp = builtin.AtomicRmwOp;
diff --git a/std/net.zig b/std/net.zig
index 968c1f019fbe21117ac0e5a7b8653be3f6e9343b..bb292efd83333306021474ca8f8b6e3d6795b226 100644
--- a/std/net.zig
+++ b/std/net.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const net = @This();
diff --git a/std/os.zig b/std/os.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c686c2a0542265aaf2ad581c87669d208e492a72
--- /dev/null
+++ b/std/os.zig
@@ -0,0 +1,3432 @@
+const std = @import("std.zig");
+const builtin = @import("builtin");
+const Os = builtin.Os;
+const is_windows = builtin.os == Os.windows;
+const is_posix = switch (builtin.os) {
+ builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
+ else => false,
+};
+const os = @This();
+
+comptime {
+ assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
+}
+
+test "std.os" {
+ _ = @import("os/child_process.zig");
+ _ = @import("os/darwin.zig");
+ _ = @import("os/darwin/errno.zig");
+ _ = @import("os/get_user_id.zig");
+ _ = @import("os/linux.zig");
+ _ = @import("os/path.zig");
+ _ = @import("os/test.zig");
+ _ = @import("os/time.zig");
+ _ = @import("os/windows.zig");
+ _ = @import("os/uefi.zig");
+ _ = @import("os/get_app_data_dir.zig");
+}
+
+pub const windows = @import("os/windows.zig");
+pub const darwin = @import("os/darwin.zig");
+pub const linux = @import("os/linux.zig");
+pub const freebsd = @import("os/freebsd.zig");
+pub const netbsd = @import("os/netbsd.zig");
+pub const zen = @import("os/zen.zig");
+pub const uefi = @import("os/uefi.zig");
+
+pub const posix = switch (builtin.os) {
+ Os.linux => linux,
+ Os.macosx, Os.ios => darwin,
+ Os.freebsd => freebsd,
+ Os.netbsd => netbsd,
+ Os.zen => zen,
+ else => @compileError("Unsupported OS"),
+};
+
+pub const net = @import("net.zig");
+
+pub const ChildProcess = @import("os/child_process.zig").ChildProcess;
+pub const path = @import("os/path.zig");
+pub const File = @import("os/file.zig").File;
+pub const time = @import("os/time.zig");
+
+pub const page_size = 4 * 1024;
+pub const MAX_PATH_BYTES = switch (builtin.os) {
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
+ // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
+ // If it would require 4 UTF-8 bytes, then there would be a surrogate
+ // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
+ // +1 for the null byte at the end, which can be encoded in 1 byte.
+ Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
+ else => @compileError("Unsupported OS"),
+};
+
+pub const UserInfo = @import("os/get_user_id.zig").UserInfo;
+pub const getUserInfo = @import("os/get_user_id.zig").getUserInfo;
+
+const windows_util = @import("os/windows/util.zig");
+pub const windowsWaitSingle = windows_util.windowsWaitSingle;
+pub const windowsWrite = windows_util.windowsWrite;
+pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
+pub const windowsOpen = windows_util.windowsOpen;
+pub const windowsOpenW = windows_util.windowsOpenW;
+pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
+
+pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
+pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
+
+pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
+pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
+
+pub const WindowsWaitResult = windows_util.WindowsWaitResult;
+pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
+
+pub const WindowsWaitError = windows_util.WaitError;
+pub const WindowsOpenError = windows_util.OpenError;
+pub const WindowsWriteError = windows_util.WriteError;
+pub const WindowsReadError = windows_util.ReadError;
+
+pub const FileHandle = if (is_windows) windows.HANDLE else i32;
+
+pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
+pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
+
+const debug = std.debug;
+const assert = debug.assert;
+const testing = std.testing;
+
+const c = std.c;
+
+const mem = std.mem;
+const Allocator = mem.Allocator;
+
+const BufMap = std.BufMap;
+const cstr = std.cstr;
+
+const io = std.io;
+const base64 = std.base64;
+const ArrayList = std.ArrayList;
+const Buffer = std.Buffer;
+const math = std.math;
+
+/// Fills `buf` with random bytes. If linking against libc, this calls the
+/// appropriate OS-specific library call. Otherwise it uses the zig standard
+/// library implementation.
+pub fn getRandomBytes(buf: []u8) !void {
+ switch (builtin.os) {
+ Os.linux => while (true) {
+ // TODO check libc version and potentially call c.getrandom.
+ // See #397
+ const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
+ switch (errno) {
+ 0 => return,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EINTR => continue,
+ posix.ENOSYS => return getRandomBytesDevURandom(buf),
+ else => return unexpectedErrorPosix(errno),
+ }
+ },
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
+ Os.windows => {
+ // Call RtlGenRandom() instead of CryptGetRandom() on Windows
+ // https://github.com/rust-lang-nursery/rand/issues/111
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
+ if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
+ const err = windows.GetLastError();
+ return switch (err) {
+ else => unexpectedErrorWindows(err),
+ };
+ }
+ },
+ Os.zen => {
+ const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
+ var i: usize = 0;
+ while (i < buf.len) : (i += 1) {
+ if (i > randomness.len) return error.Unknown;
+ buf[i] = randomness[i];
+ }
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+fn getRandomBytesDevURandom(buf: []u8) !void {
+ const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
+ defer close(fd);
+
+ const stream = &File.openHandle(fd).inStream().stream;
+ stream.readNoEof(buf) catch |err| switch (err) {
+ error.EndOfStream => unreachable,
+ error.OperationAborted => unreachable,
+ error.BrokenPipe => unreachable,
+ error.Unexpected => return error.Unexpected,
+ error.InputOutput => return error.Unexpected,
+ error.SystemResources => return error.Unexpected,
+ error.IsDir => unreachable,
+ };
+}
+
+test "os.getRandomBytes" {
+ var buf_a: [50]u8 = undefined;
+ var buf_b: [50]u8 = undefined;
+ // Call Twice
+ try getRandomBytes(buf_a[0..]);
+ try getRandomBytes(buf_b[0..]);
+
+ // Check if random (not 100% conclusive)
+ testing.expect(!mem.eql(u8, buf_a, buf_b));
+}
+
+/// Raises a signal in the current kernel thread, ending its execution.
+/// If linking against libc, this calls the abort() libc function. Otherwise
+/// it uses the zig standard library implementation.
+pub fn abort() noreturn {
+ @setCold(true);
+ if (builtin.link_libc) {
+ c.abort();
+ }
+ switch (builtin.os) {
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ _ = posix.raise(posix.SIGABRT);
+ _ = posix.raise(posix.SIGKILL);
+ while (true) {}
+ },
+ Os.windows => {
+ if (builtin.mode == builtin.Mode.Debug) {
+ @breakpoint();
+ }
+ windows.ExitProcess(3);
+ },
+ Os.uefi => {
+ // TODO there's gotta be a better thing to do here than loop forever
+ while (true) {}
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+/// Exits the program cleanly with the specified status code.
+pub fn exit(status: u8) noreturn {
+ @setCold(true);
+ if (builtin.link_libc) {
+ c.exit(status);
+ }
+ switch (builtin.os) {
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ posix.exit(status);
+ },
+ Os.windows => {
+ windows.ExitProcess(status);
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+/// When a file descriptor is closed on linux, it pops the first
+/// node from this queue and resumes it.
+/// Async functions which get the EMFILE error code can suspend,
+/// putting their coroutine handle into this list.
+/// TODO make this an atomic linked list
+pub var emfile_promise_queue = std.LinkedList(promise).init();
+
+/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
+pub fn close(handle: FileHandle) void {
+ if (is_windows) {
+ windows_util.windowsClose(handle);
+ } else {
+ while (true) {
+ const err = posix.getErrno(posix.close(handle));
+ switch (err) {
+ posix.EINTR => continue,
+ else => {
+ if (emfile_promise_queue.popFirst()) |p| resume p.data;
+ return;
+ },
+ }
+ }
+ }
+}
+
+pub const PosixReadError = error{
+ InputOutput,
+ SystemResources,
+ IsDir,
+ Unexpected,
+};
+
+/// Returns the number of bytes that were read, which can be less than
+/// buf.len. If 0 bytes were read, that means EOF.
+pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
+ // Linux can return EINVAL when read amount is > 0x7ffff000
+ // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
+ const max_buf_len = 0x7ffff000;
+
+ var index: usize = 0;
+ while (index < buf.len) {
+ const want_to_read = math.min(buf.len - index, usize(max_buf_len));
+ const rc = posix.read(fd, buf.ptr + index, want_to_read);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => {
+ index += rc;
+ if (rc == want_to_read) continue;
+ // Read returned less than buf.len.
+ return index;
+ },
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EAGAIN => unreachable,
+ posix.EBADF => unreachable, // always a race condition
+ posix.EIO => return error.InputOutput,
+ posix.EISDIR => return error.IsDir,
+ posix.ENOBUFS => return error.SystemResources,
+ posix.ENOMEM => return error.SystemResources,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ return index;
+}
+
+/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
+pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
+ switch (builtin.os) {
+ builtin.Os.macosx => {
+ // Darwin does not have preadv but it does have pread.
+ var off: usize = 0;
+ var iov_i: usize = 0;
+ var inner_off: usize = 0;
+ while (true) {
+ const v = iov[iov_i];
+ const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+ const err = darwin.getErrno(rc);
+ switch (err) {
+ 0 => {
+ off += rc;
+ inner_off += rc;
+ if (inner_off == v.iov_len) {
+ iov_i += 1;
+ inner_off = 0;
+ if (iov_i == count) {
+ return off;
+ }
+ }
+ if (rc == 0) return off; // EOF
+ continue;
+ },
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.ESPIPE => unreachable, // fd is not seekable
+ posix.EAGAIN => unreachable, // this function is not for non blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.EIO => return error.InputOutput,
+ posix.EISDIR => return error.IsDir,
+ posix.ENOBUFS => return error.SystemResources,
+ posix.ENOMEM => return error.SystemResources,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ },
+ builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
+ const rc = posix.preadv(fd, iov, count, offset);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return rc,
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EAGAIN => unreachable, // don't call this function for non blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.EIO => return error.InputOutput,
+ posix.EISDIR => return error.IsDir,
+ posix.ENOBUFS => return error.SystemResources,
+ posix.ENOMEM => return error.SystemResources,
+ else => return unexpectedErrorPosix(err),
+ }
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+pub const PosixWriteError = error{
+ DiskQuota,
+ FileTooBig,
+ InputOutput,
+ NoSpaceLeft,
+ AccessDenied,
+ BrokenPipe,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+/// Calls POSIX write, and keeps trying if it gets interrupted.
+pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
+ // Linux can return EINVAL when write amount is > 0x7ffff000
+ // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
+ const max_bytes_len = 0x7ffff000;
+
+ var index: usize = 0;
+ while (index < bytes.len) {
+ const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
+ const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
+ const write_err = posix.getErrno(rc);
+ switch (write_err) {
+ 0 => {
+ index += rc;
+ continue;
+ },
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.EDESTADDRREQ => unreachable, // connect was never called
+ posix.EDQUOT => return PosixWriteError.DiskQuota,
+ posix.EFBIG => return PosixWriteError.FileTooBig,
+ posix.EIO => return PosixWriteError.InputOutput,
+ posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
+ posix.EPERM => return PosixWriteError.AccessDenied,
+ posix.EPIPE => return PosixWriteError.BrokenPipe,
+ else => return unexpectedErrorPosix(write_err),
+ }
+ }
+}
+
+pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
+ switch (builtin.os) {
+ builtin.Os.macosx => {
+ // Darwin does not have pwritev but it does have pwrite.
+ var off: usize = 0;
+ var iov_i: usize = 0;
+ var inner_off: usize = 0;
+ while (true) {
+ const v = iov[iov_i];
+ const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+ const err = darwin.getErrno(rc);
+ switch (err) {
+ 0 => {
+ off += rc;
+ inner_off += rc;
+ if (inner_off == v.iov_len) {
+ iov_i += 1;
+ inner_off = 0;
+ if (iov_i == count) {
+ return;
+ }
+ }
+ continue;
+ },
+ posix.EINTR => continue,
+ posix.ESPIPE => unreachable, // fd is not seekable
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.EDESTADDRREQ => unreachable, // connect was never called
+ posix.EDQUOT => return PosixWriteError.DiskQuota,
+ posix.EFBIG => return PosixWriteError.FileTooBig,
+ posix.EIO => return PosixWriteError.InputOutput,
+ posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
+ posix.EPERM => return PosixWriteError.AccessDenied,
+ posix.EPIPE => return PosixWriteError.BrokenPipe,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ },
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
+ const rc = posix.pwritev(fd, iov, count, offset);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.EDESTADDRREQ => unreachable, // connect was never called
+ posix.EDQUOT => return PosixWriteError.DiskQuota,
+ posix.EFBIG => return PosixWriteError.FileTooBig,
+ posix.EIO => return PosixWriteError.InputOutput,
+ posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
+ posix.EPERM => return PosixWriteError.AccessDenied,
+ posix.EPIPE => return PosixWriteError.BrokenPipe,
+ else => return unexpectedErrorPosix(err),
+ }
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+pub const PosixOpenError = error{
+ AccessDenied,
+ FileTooBig,
+ IsDir,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ NameTooLong,
+ SystemFdQuotaExceeded,
+ NoDevice,
+ FileNotFound,
+ SystemResources,
+ NoSpaceLeft,
+ NotDir,
+ PathAlreadyExists,
+ DeviceBusy,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+/// ::file_path needs to be copied in memory to add a null terminating byte.
+/// Calls POSIX open, keeps trying if it gets interrupted, and translates
+/// the return value into zig errors.
+pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
+ const file_path_c = try toPosixPath(file_path);
+ return posixOpenC(&file_path_c, flags, perm);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
+ while (true) {
+ const result = posix.open(file_path, flags, perm);
+ const err = posix.getErrno(result);
+ if (err > 0) {
+ switch (err) {
+ posix.EINTR => continue,
+
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EACCES => return PosixOpenError.AccessDenied,
+ posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
+ posix.EISDIR => return PosixOpenError.IsDir,
+ posix.ELOOP => return PosixOpenError.SymLinkLoop,
+ posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
+ posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
+ posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
+ posix.ENODEV => return PosixOpenError.NoDevice,
+ posix.ENOENT => return PosixOpenError.FileNotFound,
+ posix.ENOMEM => return PosixOpenError.SystemResources,
+ posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
+ posix.ENOTDIR => return PosixOpenError.NotDir,
+ posix.EPERM => return PosixOpenError.AccessDenied,
+ posix.EEXIST => return PosixOpenError.PathAlreadyExists,
+ posix.EBUSY => return PosixOpenError.DeviceBusy,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ return @intCast(i32, result);
+ }
+}
+
+/// Used to convert a slice to a null terminated slice on the stack.
+/// TODO well defined copy elision
+pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
+ var path_with_null: [posix.PATH_MAX]u8 = undefined;
+ if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
+ mem.copy(u8, path_with_null[0..], file_path);
+ path_with_null[file_path.len] = 0;
+ return path_with_null;
+}
+
+pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
+ while (true) {
+ const err = posix.getErrno(posix.dup2(old_fd, new_fd));
+ if (err > 0) {
+ return switch (err) {
+ posix.EBUSY, posix.EINTR => continue,
+ posix.EMFILE => error.ProcessFdQuotaExceeded,
+ posix.EINVAL => unreachable,
+ else => unexpectedErrorPosix(err),
+ };
+ }
+ return;
+ }
+}
+
+pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
+ const envp_count = env_map.count();
+ const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
+ mem.set(?[*]u8, envp_buf, null);
+ errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
+ {
+ var it = env_map.iterator();
+ var i: usize = 0;
+ while (it.next()) |pair| : (i += 1) {
+ const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
+ @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
+ env_buf[pair.key.len] = '=';
+ @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
+ env_buf[env_buf.len - 1] = 0;
+
+ envp_buf[i] = env_buf.ptr;
+ }
+ assert(i == envp_count);
+ }
+ assert(envp_buf[envp_count] == null);
+ return envp_buf;
+}
+
+pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
+ for (envp_buf) |env| {
+ const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
+ allocator.free(env_buf);
+ }
+ allocator.free(envp_buf);
+}
+
+/// This function must allocate memory to add a null terminating bytes on path and each arg.
+/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
+/// pointers after the args and after the environment variables.
+/// `argv[0]` is the executable path.
+/// This function also uses the PATH environment variable to get the full path to the executable.
+pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
+ const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
+ mem.set(?[*]u8, argv_buf, null);
+ defer {
+ for (argv_buf) |arg| {
+ const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
+ allocator.free(arg_buf);
+ }
+ allocator.free(argv_buf);
+ }
+ for (argv) |arg, i| {
+ const arg_buf = try allocator.alloc(u8, arg.len + 1);
+ @memcpy(arg_buf.ptr, arg.ptr, arg.len);
+ arg_buf[arg.len] = 0;
+
+ argv_buf[i] = arg_buf.ptr;
+ }
+ argv_buf[argv.len] = null;
+
+ const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
+ defer freeNullDelimitedEnvMap(allocator, envp_buf);
+
+ const exe_path = argv[0];
+ if (mem.indexOfScalar(u8, exe_path, '/') != null) {
+ return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
+ }
+
+ const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
+ // PATH.len because it is >= the largest search_path
+ // +1 for the / to join the search path and exe_path
+ // +1 for the null terminating byte
+ const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
+ defer allocator.free(path_buf);
+ var it = mem.tokenize(PATH, ":");
+ var seen_eacces = false;
+ var err: usize = undefined;
+ while (it.next()) |search_path| {
+ mem.copy(u8, path_buf, search_path);
+ path_buf[search_path.len] = '/';
+ mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
+ path_buf[search_path.len + exe_path.len + 1] = 0;
+ err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
+ assert(err > 0);
+ if (err == posix.EACCES) {
+ seen_eacces = true;
+ } else if (err != posix.ENOENT) {
+ return posixExecveErrnoToErr(err);
+ }
+ }
+ if (seen_eacces) {
+ err = posix.EACCES;
+ }
+ return posixExecveErrnoToErr(err);
+}
+
+pub const PosixExecveError = error{
+ SystemResources,
+ AccessDenied,
+ InvalidExe,
+ FileSystem,
+ IsDir,
+ FileNotFound,
+ NotDir,
+ FileBusy,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+fn posixExecveErrnoToErr(err: usize) PosixExecveError {
+ assert(err > 0);
+ switch (err) {
+ posix.EFAULT => unreachable,
+ posix.E2BIG => return error.SystemResources,
+ posix.EMFILE => return error.SystemResources,
+ posix.ENAMETOOLONG => return error.SystemResources,
+ posix.ENFILE => return error.SystemResources,
+ posix.ENOMEM => return error.SystemResources,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EINVAL => return error.InvalidExe,
+ posix.ENOEXEC => return error.InvalidExe,
+ posix.EIO => return error.FileSystem,
+ posix.ELOOP => return error.FileSystem,
+ posix.EISDIR => return error.IsDir,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOTDIR => return error.NotDir,
+ posix.ETXTBSY => return error.FileBusy,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
+pub var posix_environ_raw: [][*]u8 = undefined;
+
+/// See std.elf for the constants.
+pub fn linuxGetAuxVal(index: usize) usize {
+ if (builtin.link_libc) {
+ return usize(std.c.getauxval(index));
+ } else if (linux_elf_aux_maybe) |auxv| {
+ var i: usize = 0;
+ while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
+ if (auxv[i].a_type == index)
+ return auxv[i].a_un.a_val;
+ }
+ }
+ return 0;
+}
+
+pub fn getBaseAddress() usize {
+ switch (builtin.os) {
+ builtin.Os.linux => {
+ const base = linuxGetAuxVal(std.elf.AT_BASE);
+ if (base != 0) {
+ return base;
+ }
+ const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
+ return phdr - @sizeOf(std.elf.Ehdr);
+ },
+ builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
+ return @ptrToInt(&std.c._mh_execute_header);
+ },
+ builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+/// Caller must free result when done.
+/// TODO make this go through libc when we have it
+pub fn getEnvMap(allocator: *Allocator) !BufMap {
+ var result = BufMap.init(allocator);
+ errdefer result.deinit();
+
+ if (is_windows) {
+ const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
+ defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
+
+ var i: usize = 0;
+ while (true) {
+ if (ptr[i] == 0) return result;
+
+ const key_start = i;
+
+ while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
+ const key_w = ptr[key_start..i];
+ const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
+ errdefer allocator.free(key);
+
+ if (ptr[i] == '=') i += 1;
+
+ const value_start = i;
+ while (ptr[i] != 0) : (i += 1) {}
+ const value_w = ptr[value_start..i];
+ const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
+ errdefer allocator.free(value);
+
+ i += 1; // skip over null byte
+
+ try result.setMove(key, value);
+ }
+ } else {
+ for (posix_environ_raw) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
+ const key = ptr[0..line_i];
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0) : (end_i += 1) {}
+ const value = ptr[line_i + 1 .. end_i];
+
+ try result.set(key, value);
+ }
+ return result;
+ }
+}
+
+test "os.getEnvMap" {
+ var env = try getEnvMap(std.debug.global_allocator);
+ defer env.deinit();
+}
+
+/// TODO make this go through libc when we have it
+pub fn getEnvPosix(key: []const u8) ?[]const u8 {
+ for (posix_environ_raw) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
+ const this_key = ptr[0..line_i];
+ if (!mem.eql(u8, key, this_key)) continue;
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0) : (end_i += 1) {}
+ const this_value = ptr[line_i + 1 .. end_i];
+
+ return this_value;
+ }
+ return null;
+}
+
+pub const GetEnvVarOwnedError = error{
+ OutOfMemory,
+ EnvironmentVariableNotFound,
+
+ /// See https://github.com/ziglang/zig/issues/1774
+ InvalidUtf8,
+};
+
+/// Caller must free returned memory.
+/// TODO make this go through libc when we have it
+pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
+ if (is_windows) {
+ const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
+ defer allocator.free(key_with_null);
+
+ var buf = try allocator.alloc(u16, 256);
+ defer allocator.free(buf);
+
+ while (true) {
+ const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
+ const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
+
+ if (result == 0) {
+ const err = windows.GetLastError();
+ return switch (err) {
+ windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
+ else => {
+ _ = unexpectedErrorWindows(err);
+ return error.EnvironmentVariableNotFound;
+ },
+ };
+ }
+
+ if (result > buf.len) {
+ buf = try allocator.realloc(u16, buf, result);
+ continue;
+ }
+
+ return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
+ error.DanglingSurrogateHalf => return error.InvalidUtf8,
+ error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
+ error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
+ error.OutOfMemory => return error.OutOfMemory,
+ };
+ }
+ } else {
+ const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
+ return mem.dupe(allocator, u8, result);
+ }
+}
+
+test "os.getEnvVarOwned" {
+ var ga = debug.global_allocator;
+ testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
+}
+
+/// Caller must free the returned memory.
+pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ return mem.dupe(allocator, u8, try getCwd(&buf));
+}
+
+pub const GetCwdError = error{Unexpected};
+
+/// The result is a slice of out_buffer.
+pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
+ switch (builtin.os) {
+ Os.windows => {
+ var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+ const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
+ const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
+ const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
+ if (result == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+ assert(result <= utf16le_buf.len);
+ const utf16le_slice = utf16le_buf[0..result];
+ // Trust that Windows gives us valid UTF-16LE.
+ const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
+ return out_buffer[0..end_index];
+ },
+ else => {
+ const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
+ switch (err) {
+ 0 => return cstr.toSlice(out_buffer),
+ posix.ERANGE => unreachable,
+ else => return unexpectedErrorPosix(err),
+ }
+ },
+ }
+}
+
+test "os.getCwd" {
+ // at least call it so it gets compiled
+ _ = getCwdAlloc(debug.global_allocator);
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ _ = getCwd(&buf);
+}
+
+pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
+
+/// TODO add a symLinkC variant
+pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
+ if (is_windows) {
+ return symLinkWindows(existing_path, new_path);
+ } else {
+ return symLinkPosix(existing_path, new_path);
+ }
+}
+
+pub const WindowsSymLinkError = error{
+ NameTooLong,
+ InvalidUtf8,
+ BadPathName,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
+ if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+}
+
+pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
+ const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
+ const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
+ return symLinkW(&existing_path_w, &new_path_w);
+}
+
+pub const PosixSymLinkError = error{
+ AccessDenied,
+ DiskQuota,
+ PathAlreadyExists,
+ FileSystem,
+ SymLinkLoop,
+ NameTooLong,
+ FileNotFound,
+ SystemResources,
+ NoSpaceLeft,
+ ReadOnlyFileSystem,
+ NotDir,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
+ const err = posix.getErrno(posix.symlink(existing_path, new_path));
+ switch (err) {
+ 0 => return,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EDQUOT => return error.DiskQuota,
+ posix.EEXIST => return error.PathAlreadyExists,
+ posix.EIO => return error.FileSystem,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOTDIR => return error.NotDir,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOSPC => return error.NoSpaceLeft,
+ posix.EROFS => return error.ReadOnlyFileSystem,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
+ const existing_path_c = try toPosixPath(existing_path);
+ const new_path_c = try toPosixPath(new_path);
+ return symLinkPosixC(&existing_path_c, &new_path_c);
+}
+
+// here we replace the standard +/ with -_ so that it can be used in a file name
+const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
+
+/// TODO remove the allocator requirement from this API
+pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
+ if (symLink(existing_path, new_path)) {
+ return;
+ } else |err| switch (err) {
+ error.PathAlreadyExists => {},
+ else => return err, // TODO zig should know this set does not include PathAlreadyExists
+ }
+
+ const dirname = os.path.dirname(new_path) orelse ".";
+
+ var rand_buf: [12]u8 = undefined;
+ const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
+ defer allocator.free(tmp_path);
+ mem.copy(u8, tmp_path[0..], dirname);
+ tmp_path[dirname.len] = os.path.sep;
+ while (true) {
+ try getRandomBytes(rand_buf[0..]);
+ b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
+
+ if (symLink(existing_path, tmp_path)) {
+ return rename(tmp_path, new_path);
+ } else |err| switch (err) {
+ error.PathAlreadyExists => continue,
+ else => return err, // TODO zig should know this set does not include PathAlreadyExists
+ }
+ }
+}
+
+pub const DeleteFileError = error{
+ FileNotFound,
+ AccessDenied,
+ FileBusy,
+ FileSystem,
+ IsDir,
+ SymLinkLoop,
+ NameTooLong,
+ NotDir,
+ SystemResources,
+ ReadOnlyFileSystem,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
+
+ /// On Windows, file paths cannot contain these characters:
+ /// '/', '*', '?', '"', '<', '>', '|'
+ BadPathName,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
+ if (builtin.os == Os.windows) {
+ const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
+ return deleteFileW(&file_path_w);
+ } else {
+ const file_path_c = try toPosixPath(file_path);
+ return deleteFileC(&file_path_c);
+ }
+}
+
+pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
+ if (windows.DeleteFileW(file_path) == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
+ windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
+ windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+}
+
+pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
+ if (is_windows) {
+ const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
+ return deleteFileW(&file_path_w);
+ } else {
+ const err = posix.getErrno(posix.unlink(file_path));
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EBUSY => return error.FileBusy,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EIO => return error.FileSystem,
+ posix.EISDIR => return error.IsDir,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOTDIR => return error.NotDir,
+ posix.ENOMEM => return error.SystemResources,
+ posix.EROFS => return error.ReadOnlyFileSystem,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+}
+
+/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
+/// merged and readily available,
+/// there is a possibility of power loss or application termination leaving temporary files present
+/// in the same directory as dest_path.
+/// Destination file will have the same mode as the source file.
+pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
+ var in_file = try os.File.openRead(source_path);
+ defer in_file.close();
+
+ const mode = try in_file.mode();
+
+ var atomic_file = try AtomicFile.init(dest_path, mode);
+ defer atomic_file.deinit();
+
+ var buf: [page_size]u8 = undefined;
+ while (true) {
+ const amt = try in_file.readFull(buf[0..]);
+ try atomic_file.file.write(buf[0..amt]);
+ if (amt != buf.len) {
+ return atomic_file.finish();
+ }
+ }
+}
+
+/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
+/// merged and readily available,
+/// there is a possibility of power loss or application termination leaving temporary files present
+pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
+ var in_file = try os.File.openRead(source_path);
+ defer in_file.close();
+
+ var atomic_file = try AtomicFile.init(dest_path, mode);
+ defer atomic_file.deinit();
+
+ var buf: [page_size]u8 = undefined;
+ while (true) {
+ const amt = try in_file.read(buf[0..]);
+ try atomic_file.file.write(buf[0..amt]);
+ if (amt != buf.len) {
+ return atomic_file.finish();
+ }
+ }
+}
+
+pub const AtomicFile = struct {
+ file: os.File,
+ tmp_path_buf: [MAX_PATH_BYTES]u8,
+ dest_path: []const u8,
+ finished: bool,
+
+ const InitError = os.File.OpenError;
+
+ /// dest_path must remain valid for the lifetime of AtomicFile
+ /// call finish to atomically replace dest_path with contents
+ /// TODO once we have null terminated pointers, use the
+ /// openWriteNoClobberN function
+ pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
+ const dirname = os.path.dirname(dest_path);
+ var rand_buf: [12]u8 = undefined;
+ const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
+ const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
+ const tmp_path_len = dirname_component_len + encoded_rand_len;
+ var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
+ if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
+
+ if (dirname) |dir| {
+ mem.copy(u8, tmp_path_buf[0..], dir);
+ tmp_path_buf[dir.len] = os.path.sep;
+ }
+
+ tmp_path_buf[tmp_path_len] = 0;
+
+ while (true) {
+ try getRandomBytes(rand_buf[0..]);
+ b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
+
+ const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
+ error.PathAlreadyExists => continue,
+ // TODO zig should figure out that this error set does not include PathAlreadyExists since
+ // it is handled in the above switch
+ else => return err,
+ };
+
+ return AtomicFile{
+ .file = file,
+ .tmp_path_buf = tmp_path_buf,
+ .dest_path = dest_path,
+ .finished = false,
+ };
+ }
+ }
+
+ /// always call deinit, even after successful finish()
+ pub fn deinit(self: *AtomicFile) void {
+ if (!self.finished) {
+ self.file.close();
+ deleteFileC(&self.tmp_path_buf) catch {};
+ self.finished = true;
+ }
+ }
+
+ pub fn finish(self: *AtomicFile) !void {
+ assert(!self.finished);
+ self.file.close();
+ self.finished = true;
+ if (is_posix) {
+ const dest_path_c = try toPosixPath(self.dest_path);
+ return renameC(&self.tmp_path_buf, &dest_path_c);
+ } else if (is_windows) {
+ const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
+ const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
+ return renameW(&tmp_path_w, &dest_path_w);
+ } else {
+ @compileError("Unsupported OS");
+ }
+ }
+};
+
+pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
+ if (is_windows) {
+ const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
+ const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
+ return renameW(&old_path_w, &new_path_w);
+ } else {
+ const err = posix.getErrno(posix.rename(old_path, new_path));
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EBUSY => return error.FileBusy,
+ posix.EDQUOT => return error.DiskQuota,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EISDIR => return error.IsDir,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.EMLINK => return error.LinkQuotaExceeded,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOTDIR => return error.NotDir,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOSPC => return error.NoSpaceLeft,
+ posix.EEXIST => return error.PathAlreadyExists,
+ posix.ENOTEMPTY => return error.PathAlreadyExists,
+ posix.EROFS => return error.ReadOnlyFileSystem,
+ posix.EXDEV => return error.RenameAcrossMountPoints,
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+}
+
+pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
+ const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
+ if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+}
+
+pub fn rename(old_path: []const u8, new_path: []const u8) !void {
+ if (is_windows) {
+ const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
+ const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
+ return renameW(&old_path_w, &new_path_w);
+ } else {
+ const old_path_c = try toPosixPath(old_path);
+ const new_path_c = try toPosixPath(new_path);
+ return renameC(&old_path_c, &new_path_c);
+ }
+}
+
+pub fn makeDir(dir_path: []const u8) !void {
+ if (is_windows) {
+ return makeDirWindows(dir_path);
+ } else {
+ return makeDirPosix(dir_path);
+ }
+}
+
+pub fn makeDirWindows(dir_path: []const u8) !void {
+ const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
+
+ if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
+ const err = windows.GetLastError();
+ return switch (err) {
+ windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
+ windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
+ else => unexpectedErrorWindows(err),
+ };
+ }
+}
+
+pub fn makeDirPosixC(dir_path: [*]const u8) !void {
+ const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EDQUOT => return error.DiskQuota,
+ posix.EEXIST => return error.PathAlreadyExists,
+ posix.EFAULT => unreachable,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.EMLINK => return error.LinkQuotaExceeded,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOSPC => return error.NoSpaceLeft,
+ posix.ENOTDIR => return error.NotDir,
+ posix.EROFS => return error.ReadOnlyFileSystem,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub fn makeDirPosix(dir_path: []const u8) !void {
+ const dir_path_c = try toPosixPath(dir_path);
+ return makeDirPosixC(&dir_path_c);
+}
+
+/// Calls makeDir recursively to make an entire path. Returns success if the path
+/// already exists and is a directory.
+/// TODO determine if we can remove the allocator requirement from this function
+pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
+ const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
+ defer allocator.free(resolved_path);
+
+ var end_index: usize = resolved_path.len;
+ while (true) {
+ makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
+ error.PathAlreadyExists => {
+ // TODO stat the file and return an error if it's not a directory
+ // this is important because otherwise a dangling symlink
+ // could cause an infinite loop
+ if (end_index == resolved_path.len) return;
+ },
+ error.FileNotFound => {
+ // march end_index backward until next path component
+ while (true) {
+ end_index -= 1;
+ if (os.path.isSep(resolved_path[end_index])) break;
+ }
+ continue;
+ },
+ else => return err,
+ };
+ if (end_index == resolved_path.len) return;
+ // march end_index forward until next path component
+ while (true) {
+ end_index += 1;
+ if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
+ }
+ }
+}
+
+pub const DeleteDirError = error{
+ AccessDenied,
+ FileBusy,
+ SymLinkLoop,
+ NameTooLong,
+ FileNotFound,
+ SystemResources,
+ NotDir,
+ DirNotEmpty,
+ ReadOnlyFileSystem,
+ InvalidUtf8,
+ BadPathName,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
+ switch (builtin.os) {
+ Os.windows => {
+ const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
+ return deleteDirW(&dir_path_w);
+ },
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ const err = posix.getErrno(posix.rmdir(dir_path));
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return error.AccessDenied,
+ posix.EPERM => return error.AccessDenied,
+ posix.EBUSY => return error.FileBusy,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOTDIR => return error.NotDir,
+ posix.EEXIST => return error.DirNotEmpty,
+ posix.ENOTEMPTY => return error.DirNotEmpty,
+ posix.EROFS => return error.ReadOnlyFileSystem,
+ else => return unexpectedErrorPosix(err),
+ }
+ },
+ else => @compileError("unimplemented"),
+ }
+}
+
+pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
+ if (windows.RemoveDirectoryW(dir_path_w) == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+}
+
+/// Returns ::error.DirNotEmpty if the directory is not empty.
+/// To delete a directory recursively, see ::deleteTree
+pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
+ switch (builtin.os) {
+ Os.windows => {
+ const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
+ return deleteDirW(&dir_path_w);
+ },
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ const dir_path_c = try toPosixPath(dir_path);
+ return deleteDirC(&dir_path_c);
+ },
+ else => @compileError("unimplemented"),
+ }
+}
+
+/// Whether ::full_path describes a symlink, file, or directory, this function
+/// removes it. If it cannot be removed because it is a non-empty directory,
+/// this function recursively removes its entries and then tries again.
+const DeleteTreeError = error{
+ OutOfMemory,
+ AccessDenied,
+ FileTooBig,
+ IsDir,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ NameTooLong,
+ SystemFdQuotaExceeded,
+ NoDevice,
+ SystemResources,
+ NoSpaceLeft,
+ PathAlreadyExists,
+ ReadOnlyFileSystem,
+ NotDir,
+ FileNotFound,
+ FileSystem,
+ FileBusy,
+ DirNotEmpty,
+ DeviceBusy,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
+
+ /// On Windows, file paths cannot contain these characters:
+ /// '/', '*', '?', '"', '<', '>', '|'
+ BadPathName,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+/// TODO determine if we can remove the allocator requirement
+pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
+ start_over: while (true) {
+ var got_access_denied = false;
+ // First, try deleting the item as a file. This way we don't follow sym links.
+ if (deleteFile(full_path)) {
+ return;
+ } else |err| switch (err) {
+ error.FileNotFound => return,
+ error.IsDir => {},
+ error.AccessDenied => got_access_denied = true,
+
+ error.InvalidUtf8,
+ error.SymLinkLoop,
+ error.NameTooLong,
+ error.SystemResources,
+ error.ReadOnlyFileSystem,
+ error.NotDir,
+ error.FileSystem,
+ error.FileBusy,
+ error.BadPathName,
+ error.Unexpected,
+ => return err,
+ }
+ {
+ var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
+ error.NotDir => {
+ if (got_access_denied) {
+ return error.AccessDenied;
+ }
+ continue :start_over;
+ },
+
+ error.OutOfMemory,
+ error.AccessDenied,
+ error.FileTooBig,
+ error.IsDir,
+ error.SymLinkLoop,
+ error.ProcessFdQuotaExceeded,
+ error.NameTooLong,
+ error.SystemFdQuotaExceeded,
+ error.NoDevice,
+ error.FileNotFound,
+ error.SystemResources,
+ error.NoSpaceLeft,
+ error.PathAlreadyExists,
+ error.Unexpected,
+ error.InvalidUtf8,
+ error.BadPathName,
+ error.DeviceBusy,
+ => return err,
+ };
+ defer dir.close();
+
+ var full_entry_buf = ArrayList(u8).init(allocator);
+ defer full_entry_buf.deinit();
+
+ while (try dir.next()) |entry| {
+ try full_entry_buf.resize(full_path.len + entry.name.len + 1);
+ const full_entry_path = full_entry_buf.toSlice();
+ mem.copy(u8, full_entry_path, full_path);
+ full_entry_path[full_path.len] = path.sep;
+ mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
+
+ try deleteTree(allocator, full_entry_path);
+ }
+ }
+ return deleteDir(full_path);
+ }
+}
+
+pub const Dir = struct {
+ handle: Handle,
+ allocator: *Allocator,
+
+ pub const Handle = switch (builtin.os) {
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
+ fd: i32,
+ seek: i64,
+ buf: []u8,
+ index: usize,
+ end_index: usize,
+ },
+ Os.linux => struct {
+ fd: i32,
+ buf: []u8,
+ index: usize,
+ end_index: usize,
+ },
+ Os.windows => struct {
+ handle: windows.HANDLE,
+ find_file_data: windows.WIN32_FIND_DATAW,
+ first: bool,
+ name_data: [256]u8,
+ },
+ else => @compileError("unimplemented"),
+ };
+
+ pub const Entry = struct {
+ name: []const u8,
+ kind: Kind,
+
+ pub const Kind = enum {
+ BlockDevice,
+ CharacterDevice,
+ Directory,
+ NamedPipe,
+ SymLink,
+ File,
+ UnixDomainSocket,
+ Whiteout,
+ Unknown,
+ };
+ };
+
+ pub const OpenError = error{
+ FileNotFound,
+ NotDir,
+ AccessDenied,
+ FileTooBig,
+ IsDir,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ NameTooLong,
+ SystemFdQuotaExceeded,
+ NoDevice,
+ SystemResources,
+ NoSpaceLeft,
+ PathAlreadyExists,
+ OutOfMemory,
+ InvalidUtf8,
+ BadPathName,
+ DeviceBusy,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+ };
+
+ /// TODO remove the allocator requirement from this API
+ pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
+ return Dir{
+ .allocator = allocator,
+ .handle = switch (builtin.os) {
+ Os.windows => blk: {
+ var find_file_data: windows.WIN32_FIND_DATAW = undefined;
+ const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
+ break :blk Handle{
+ .handle = handle,
+ .find_file_data = find_file_data, // TODO guaranteed copy elision
+ .first = true,
+ .name_data = undefined,
+ };
+ },
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
+ .fd = try posixOpen(
+ dir_path,
+ posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
+ 0,
+ ),
+ .seek = 0,
+ .index = 0,
+ .end_index = 0,
+ .buf = []u8{},
+ },
+ Os.linux => Handle{
+ .fd = try posixOpen(
+ dir_path,
+ posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
+ 0,
+ ),
+ .index = 0,
+ .end_index = 0,
+ .buf = []u8{},
+ },
+ else => @compileError("unimplemented"),
+ },
+ };
+ }
+
+ pub fn close(self: *Dir) void {
+ switch (builtin.os) {
+ Os.windows => {
+ _ = windows.FindClose(self.handle.handle);
+ },
+ Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
+ self.allocator.free(self.handle.buf);
+ os.close(self.handle.fd);
+ },
+ else => @compileError("unimplemented"),
+ }
+ }
+
+ /// Memory such as file names referenced in this returned entry becomes invalid
+ /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
+ pub fn next(self: *Dir) !?Entry {
+ switch (builtin.os) {
+ Os.linux => return self.nextLinux(),
+ Os.macosx, Os.ios => return self.nextDarwin(),
+ Os.windows => return self.nextWindows(),
+ Os.freebsd => return self.nextFreebsd(),
+ Os.netbsd => return self.nextFreebsd(),
+ else => @compileError("unimplemented"),
+ }
+ }
+
+ fn nextDarwin(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, page_size);
+ }
+
+ while (true) {
+ const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
+ const err = posix.getErrno(result);
+ if (err > 0) {
+ switch (err) {
+ posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
+ posix.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ if (result == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = result;
+ break;
+ }
+ }
+ const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + darwin_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
+
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (darwin_entry.d_type) {
+ posix.DT_BLK => Entry.Kind.BlockDevice,
+ posix.DT_CHR => Entry.Kind.CharacterDevice,
+ posix.DT_DIR => Entry.Kind.Directory,
+ posix.DT_FIFO => Entry.Kind.NamedPipe,
+ posix.DT_LNK => Entry.Kind.SymLink,
+ posix.DT_REG => Entry.Kind.File,
+ posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ posix.DT_WHT => Entry.Kind.Whiteout,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+
+ fn nextWindows(self: *Dir) !?Entry {
+ while (true) {
+ if (self.handle.first) {
+ self.handle.first = false;
+ } else {
+ if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
+ return null;
+ }
+ const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
+ if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
+ continue;
+ // Trust that Windows gives us valid UTF-16LE
+ const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
+ const name_utf8 = self.handle.name_data[0..name_utf8_len];
+ const kind = blk: {
+ const attrs = self.handle.find_file_data.dwFileAttributes;
+ if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
+ if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
+ if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
+ break :blk Entry.Kind.Unknown;
+ };
+ return Entry{
+ .name = name_utf8,
+ .kind = kind,
+ };
+ }
+ }
+
+ fn nextLinux(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, page_size);
+ }
+
+ while (true) {
+ const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
+ const err = posix.getErrno(result);
+ if (err > 0) {
+ switch (err) {
+ posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
+ posix.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ if (result == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = result;
+ break;
+ }
+ }
+ const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + linux_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
+
+ // skip . and .. entries
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (linux_entry.d_type) {
+ posix.DT_BLK => Entry.Kind.BlockDevice,
+ posix.DT_CHR => Entry.Kind.CharacterDevice,
+ posix.DT_DIR => Entry.Kind.Directory,
+ posix.DT_FIFO => Entry.Kind.NamedPipe,
+ posix.DT_LNK => Entry.Kind.SymLink,
+ posix.DT_REG => Entry.Kind.File,
+ posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+
+ fn nextFreebsd(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, page_size);
+ }
+
+ while (true) {
+ const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
+ const err = posix.getErrno(result);
+ if (err > 0) {
+ switch (err) {
+ posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
+ posix.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ if (result == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = result;
+ break;
+ }
+ }
+ const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + freebsd_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
+
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (freebsd_entry.d_type) {
+ posix.DT_BLK => Entry.Kind.BlockDevice,
+ posix.DT_CHR => Entry.Kind.CharacterDevice,
+ posix.DT_DIR => Entry.Kind.Directory,
+ posix.DT_FIFO => Entry.Kind.NamedPipe,
+ posix.DT_LNK => Entry.Kind.SymLink,
+ posix.DT_REG => Entry.Kind.File,
+ posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ posix.DT_WHT => Entry.Kind.Whiteout,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+};
+
+pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
+ const path_buf = try allocator.alloc(u8, dir_path.len + 1);
+ defer allocator.free(path_buf);
+
+ mem.copy(u8, path_buf, dir_path);
+ path_buf[dir_path.len] = 0;
+
+ const err = posix.getErrno(posix.chdir(path_buf.ptr));
+ if (err > 0) {
+ return switch (err) {
+ posix.EACCES => error.AccessDenied,
+ posix.EFAULT => unreachable,
+ posix.EIO => error.FileSystem,
+ posix.ELOOP => error.SymLinkLoop,
+ posix.ENAMETOOLONG => error.NameTooLong,
+ posix.ENOENT => error.FileNotFound,
+ posix.ENOMEM => error.SystemResources,
+ posix.ENOTDIR => error.NotDir,
+ else => unexpectedErrorPosix(err),
+ };
+ }
+}
+
+/// Read value of a symbolic link.
+/// The return value is a slice of out_buffer.
+pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
+ const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return out_buffer[0..rc],
+ posix.EACCES => return error.AccessDenied,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EIO => return error.FileSystem,
+ posix.ELOOP => return error.SymLinkLoop,
+ posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOTDIR => return error.NotDir,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+/// Read value of a symbolic link.
+/// The return value is a slice of out_buffer.
+pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
+ const file_path_c = try toPosixPath(file_path);
+ return readLinkC(out_buffer, &file_path_c);
+}
+
+pub fn posix_setuid(uid: u32) !void {
+ const err = posix.getErrno(posix.setuid(uid));
+ if (err == 0) return;
+ return switch (err) {
+ posix.EAGAIN => error.ResourceLimitReached,
+ posix.EINVAL => error.InvalidUserId,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+}
+
+pub fn posix_setreuid(ruid: u32, euid: u32) !void {
+ const err = posix.getErrno(posix.setreuid(ruid, euid));
+ if (err == 0) return;
+ return switch (err) {
+ posix.EAGAIN => error.ResourceLimitReached,
+ posix.EINVAL => error.InvalidUserId,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+}
+
+pub fn posix_setgid(gid: u32) !void {
+ const err = posix.getErrno(posix.setgid(gid));
+ if (err == 0) return;
+ return switch (err) {
+ posix.EAGAIN => error.ResourceLimitReached,
+ posix.EINVAL => error.InvalidUserId,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+}
+
+pub fn posix_setregid(rgid: u32, egid: u32) !void {
+ const err = posix.getErrno(posix.setregid(rgid, egid));
+ if (err == 0) return;
+ return switch (err) {
+ posix.EAGAIN => error.ResourceLimitReached,
+ posix.EINVAL => error.InvalidUserId,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+}
+
+pub const WindowsGetStdHandleErrs = error{
+ NoStdHandles,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
+ if (windows.GetStdHandle(handle_id)) |handle| {
+ if (handle == windows.INVALID_HANDLE_VALUE) {
+ const err = windows.GetLastError();
+ return switch (err) {
+ else => os.unexpectedErrorWindows(err),
+ };
+ }
+ return handle;
+ } else {
+ return error.NoStdHandles;
+ }
+}
+
+pub const ArgIteratorPosix = struct {
+ index: usize,
+ count: usize,
+
+ pub fn init() ArgIteratorPosix {
+ return ArgIteratorPosix{
+ .index = 0,
+ .count = raw.len,
+ };
+ }
+
+ pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
+ if (self.index == self.count) return null;
+
+ const s = raw[self.index];
+ self.index += 1;
+ return cstr.toSlice(s);
+ }
+
+ pub fn skip(self: *ArgIteratorPosix) bool {
+ if (self.index == self.count) return false;
+
+ self.index += 1;
+ return true;
+ }
+
+ /// This is marked as public but actually it's only meant to be used
+ /// internally by zig's startup code.
+ pub var raw: [][*]u8 = undefined;
+};
+
+pub const ArgIteratorWindows = struct {
+ index: usize,
+ cmd_line: [*]const u8,
+ in_quote: bool,
+ quote_count: usize,
+ seen_quote_count: usize,
+
+ pub const NextError = error{OutOfMemory};
+
+ pub fn init() ArgIteratorWindows {
+ return initWithCmdLine(windows.GetCommandLineA());
+ }
+
+ pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
+ return ArgIteratorWindows{
+ .index = 0,
+ .cmd_line = cmd_line,
+ .in_quote = false,
+ .quote_count = countQuotes(cmd_line),
+ .seen_quote_count = 0,
+ };
+ }
+
+ /// You must free the returned memory when done.
+ pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
+ // march forward over whitespace
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return null,
+ ' ', '\t' => continue,
+ else => break,
+ }
+ }
+
+ return self.internalNext(allocator);
+ }
+
+ pub fn skip(self: *ArgIteratorWindows) bool {
+ // march forward over whitespace
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return false,
+ ' ', '\t' => continue,
+ else => break,
+ }
+ }
+
+ var backslash_count: usize = 0;
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return true,
+ '"' => {
+ const quote_is_real = backslash_count % 2 == 0;
+ if (quote_is_real) {
+ self.seen_quote_count += 1;
+ }
+ },
+ '\\' => {
+ backslash_count += 1;
+ },
+ ' ', '\t' => {
+ if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
+ return true;
+ }
+ backslash_count = 0;
+ },
+ else => {
+ backslash_count = 0;
+ continue;
+ },
+ }
+ }
+ }
+
+ fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
+ var buf = try Buffer.initSize(allocator, 0);
+ defer buf.deinit();
+
+ var backslash_count: usize = 0;
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return buf.toOwnedSlice(),
+ '"' => {
+ const quote_is_real = backslash_count % 2 == 0;
+ try self.emitBackslashes(&buf, backslash_count / 2);
+ backslash_count = 0;
+
+ if (quote_is_real) {
+ self.seen_quote_count += 1;
+ if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
+ try buf.appendByte('"');
+ }
+ } else {
+ try buf.appendByte('"');
+ }
+ },
+ '\\' => {
+ backslash_count += 1;
+ },
+ ' ', '\t' => {
+ try self.emitBackslashes(&buf, backslash_count);
+ backslash_count = 0;
+ if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
+ try buf.appendByte(byte);
+ } else {
+ return buf.toOwnedSlice();
+ }
+ },
+ else => {
+ try self.emitBackslashes(&buf, backslash_count);
+ backslash_count = 0;
+ try buf.appendByte(byte);
+ },
+ }
+ }
+ }
+
+ fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
+ var i: usize = 0;
+ while (i < emit_count) : (i += 1) {
+ try buf.appendByte('\\');
+ }
+ }
+
+ fn countQuotes(cmd_line: [*]const u8) usize {
+ var result: usize = 0;
+ var backslash_count: usize = 0;
+ var index: usize = 0;
+ while (true) : (index += 1) {
+ const byte = cmd_line[index];
+ switch (byte) {
+ 0 => return result,
+ '\\' => backslash_count += 1,
+ '"' => {
+ result += 1 - (backslash_count % 2);
+ backslash_count = 0;
+ },
+ else => {
+ backslash_count = 0;
+ },
+ }
+ }
+ }
+};
+
+pub const ArgIterator = struct {
+ const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
+
+ inner: InnerType,
+
+ pub fn init() ArgIterator {
+ return ArgIterator{ .inner = InnerType.init() };
+ }
+
+ pub const NextError = ArgIteratorWindows.NextError;
+
+ /// You must free the returned memory when done.
+ pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
+ if (builtin.os == Os.windows) {
+ return self.inner.next(allocator);
+ } else {
+ return mem.dupe(allocator, u8, self.inner.next() orelse return null);
+ }
+ }
+
+ /// If you only are targeting posix you can call this and not need an allocator.
+ pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
+ return self.inner.next();
+ }
+
+ /// Parse past 1 argument without capturing it.
+ /// Returns `true` if skipped an arg, `false` if we are at the end.
+ pub fn skip(self: *ArgIterator) bool {
+ return self.inner.skip();
+ }
+};
+
+pub fn args() ArgIterator {
+ return ArgIterator.init();
+}
+
+/// Caller must call argsFree on result.
+pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
+ // TODO refactor to only make 1 allocation.
+ var it = args();
+ var contents = try Buffer.initSize(allocator, 0);
+ defer contents.deinit();
+
+ var slice_list = ArrayList(usize).init(allocator);
+ defer slice_list.deinit();
+
+ while (it.next(allocator)) |arg_or_err| {
+ const arg = try arg_or_err;
+ defer allocator.free(arg);
+ try contents.append(arg);
+ try slice_list.append(arg.len);
+ }
+
+ const contents_slice = contents.toSliceConst();
+ const slice_sizes = slice_list.toSliceConst();
+ const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
+ const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
+ const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
+ errdefer allocator.free(buf);
+
+ const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
+ const result_contents = buf[slice_list_bytes..];
+ mem.copy(u8, result_contents, contents_slice);
+
+ var contents_index: usize = 0;
+ for (slice_sizes) |len, i| {
+ const new_index = contents_index + len;
+ result_slice_list[i] = result_contents[contents_index..new_index];
+ contents_index = new_index;
+ }
+
+ return result_slice_list;
+}
+
+pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
+ var total_bytes: usize = 0;
+ for (args_alloc) |arg| {
+ total_bytes += @sizeOf([]u8) + arg.len;
+ }
+ const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
+ const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
+ return allocator.free(aligned_allocated_buf);
+}
+
+test "windows arg parsing" {
+ testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
+ testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
+ testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
+ testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
+ testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
+ testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
+
+ testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
+ ".\\..\\zig-cache\\build",
+ "bin\\zig.exe",
+ ".\\..",
+ ".\\..\\zig-cache",
+ "--help",
+ });
+}
+
+fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
+ var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
+ for (expected_args) |expected_arg| {
+ const arg = it.next(debug.global_allocator).? catch unreachable;
+ testing.expectEqualSlices(u8, expected_arg, arg);
+ }
+ testing.expect(it.next(debug.global_allocator) == null);
+}
+
+// TODO make this a build variable that you can set
+const unexpected_error_tracing = false;
+const UnexpectedError = error{
+ /// The Operating System returned an undocumented error code.
+ Unexpected,
+};
+
+/// Call this when you made a syscall or something that sets errno
+/// and you get an unexpected error.
+pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
+ if (unexpected_error_tracing) {
+ debug.warn("unexpected errno: {}\n", errno);
+ debug.dumpCurrentStackTrace(null);
+ }
+ return error.Unexpected;
+}
+
+/// Call this when you made a windows DLL call or something that does SetLastError
+/// and you get an unexpected error.
+pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
+ if (unexpected_error_tracing) {
+ debug.warn("unexpected GetLastError(): {}\n", err);
+ @breakpoint();
+ debug.dumpCurrentStackTrace(null);
+ }
+ return error.Unexpected;
+}
+
+pub fn openSelfExe() !os.File {
+ switch (builtin.os) {
+ Os.linux => return os.File.openReadC(c"/proc/self/exe"),
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ const self_exe_path = try selfExePath(&buf);
+ buf[self_exe_path.len] = 0;
+ return os.File.openReadC(self_exe_path.ptr);
+ },
+ Os.windows => {
+ var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+ const wide_slice = try selfExePathW(&buf);
+ return os.File.openReadW(wide_slice.ptr);
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+test "openSelfExe" {
+ switch (builtin.os) {
+ Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
+ else => return error.SkipZigTest, // Unsupported OS.
+ }
+}
+
+pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
+ const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
+ const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
+ assert(rc <= out_buffer.len);
+ if (rc == 0) {
+ const err = windows.GetLastError();
+ switch (err) {
+ else => return unexpectedErrorWindows(err),
+ }
+ }
+ return out_buffer[0..rc];
+}
+
+/// Get the path to the current executable.
+/// If you only need the directory, use selfExeDirPath.
+/// If you only want an open file handle, use openSelfExe.
+/// This function may return an error if the current executable
+/// was deleted after spawning.
+/// Returned value is a slice of out_buffer.
+///
+/// On Linux, depends on procfs being mounted. If the currently executing binary has
+/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
+/// TODO make the return type of this a null terminated pointer
+pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
+ switch (builtin.os) {
+ Os.linux => return readLink(out_buffer, "/proc/self/exe"),
+ Os.freebsd => {
+ var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
+ var out_len: usize = out_buffer.len;
+ const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
+
+ if (err == 0) return mem.toSlice(u8, out_buffer);
+
+ return switch (err) {
+ posix.EFAULT => error.BadAdress,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+ },
+ Os.netbsd => {
+ var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
+ var out_len: usize = out_buffer.len;
+ const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
+
+ if (err == 0) return mem.toSlice(u8, out_buffer);
+
+ return switch (err) {
+ posix.EFAULT => error.BadAdress,
+ posix.EPERM => error.PermissionDenied,
+ else => unexpectedErrorPosix(err),
+ };
+ },
+ Os.windows => {
+ var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
+ const utf16le_slice = try selfExePathW(&utf16le_buf);
+ // Trust that Windows gives us valid UTF-16LE.
+ const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
+ return out_buffer[0..end_index];
+ },
+ Os.macosx, Os.ios => {
+ var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
+ const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
+ if (rc != 0) return error.NameTooLong;
+ return mem.toSlice(u8, out_buffer);
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+/// `selfExeDirPath` except allocates the result on the heap.
+/// Caller owns returned memory.
+pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
+}
+
+/// Get the directory path that contains the current executable.
+/// Returned value is a slice of out_buffer.
+pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
+ switch (builtin.os) {
+ Os.linux => {
+ // If the currently executing binary has been deleted,
+ // the file path looks something like `/a/b/c/exe (deleted)`
+ // This path cannot be opened, but it's valid for determining the directory
+ // the executable was in when it was run.
+ const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
+ // Assume that /proc/self/exe has an absolute path, and therefore dirname
+ // will not return null.
+ return path.dirname(full_exe_path).?;
+ },
+ Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ const self_exe_path = try selfExePath(out_buffer);
+ // Assume that the OS APIs return absolute paths, and therefore dirname
+ // will not return null.
+ return path.dirname(self_exe_path).?;
+ },
+ else => @compileError("Unsupported OS"),
+ }
+}
+
+pub fn isTty(handle: FileHandle) bool {
+ if (is_windows) {
+ return windows_util.windowsIsTty(handle);
+ } else {
+ if (builtin.link_libc) {
+ return c.isatty(handle) != 0;
+ } else {
+ return posix.isatty(handle);
+ }
+ }
+}
+
+pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
+ if (is_windows) {
+ return windows_util.windowsIsCygwinPty(handle);
+ } else {
+ if (builtin.link_libc) {
+ return c.isatty(handle) != 0;
+ } else {
+ return posix.isatty(handle);
+ }
+ }
+}
+
+pub const PosixSocketError = error{
+ /// Permission to create a socket of the specified type and/or
+ /// pro‐tocol is denied.
+ PermissionDenied,
+
+ /// The implementation does not support the specified address family.
+ AddressFamilyNotSupported,
+
+ /// Unknown protocol, or protocol family not available.
+ ProtocolFamilyNotAvailable,
+
+ /// The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
+
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
+
+ /// Insufficient memory is available. The socket cannot be created until sufficient
+ /// resources are freed.
+ SystemResources,
+
+ /// The protocol type or the specified protocol is not supported within this domain.
+ ProtocolNotSupported,
+};
+
+pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
+ const rc = posix.socket(domain, socket_type, protocol);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EACCES => return PosixSocketError.PermissionDenied,
+ posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
+ posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
+ posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
+ posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
+ posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub const PosixBindError = error{
+ /// The address is protected, and the user is not the superuser.
+ /// For UNIX domain sockets: Search permission is denied on a component
+ /// of the path prefix.
+ AccessDenied,
+
+ /// The given address is already in use, or in the case of Internet domain sockets,
+ /// The port number was specified as zero in the socket
+ /// address structure, but, upon attempting to bind to an ephemeral port, it was
+ /// determined that all port numbers in the ephemeral port range are currently in
+ /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
+ AddressInUse,
+
+ /// A nonexistent interface was requested or the requested address was not local.
+ AddressNotAvailable,
+
+ /// Too many symbolic links were encountered in resolving addr.
+ SymLinkLoop,
+
+ /// addr is too long.
+ NameTooLong,
+
+ /// A component in the directory prefix of the socket pathname does not exist.
+ FileNotFound,
+
+ /// Insufficient kernel memory was available.
+ SystemResources,
+
+ /// A component of the path prefix is not a directory.
+ NotDir,
+
+ /// The socket inode would reside on a read-only filesystem.
+ ReadOnlyFileSystem,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+/// addr is `&const T` where T is one of the sockaddr
+pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
+ const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ posix.EACCES => return PosixBindError.AccessDenied,
+ posix.EADDRINUSE => return PosixBindError.AddressInUse,
+ posix.EBADF => unreachable, // always a race condition if this error is returned
+ posix.EINVAL => unreachable,
+ posix.ENOTSOCK => unreachable,
+ posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
+ posix.EFAULT => unreachable,
+ posix.ELOOP => return PosixBindError.SymLinkLoop,
+ posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
+ posix.ENOENT => return PosixBindError.FileNotFound,
+ posix.ENOMEM => return PosixBindError.SystemResources,
+ posix.ENOTDIR => return PosixBindError.NotDir,
+ posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+const PosixListenError = error{
+ /// Another socket is already listening on the same port.
+ /// For Internet domain sockets, the socket referred to by sockfd had not previously
+ /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
+ /// was determined that all port numbers in the ephemeral port range are currently in
+ /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
+ AddressInUse,
+
+ /// The file descriptor sockfd does not refer to a socket.
+ FileDescriptorNotASocket,
+
+ /// The socket is not of a type that supports the listen() operation.
+ OperationNotSupported,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
+ const rc = posix.listen(sockfd, backlog);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ posix.EADDRINUSE => return PosixListenError.AddressInUse,
+ posix.EBADF => unreachable,
+ posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
+ posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub const PosixAcceptError = error{
+ ConnectionAborted,
+
+ /// The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
+
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
+
+ /// Not enough free memory. This often means that the memory allocation is limited
+ /// by the socket buffer limits, not by the system memory.
+ SystemResources,
+
+ /// The file descriptor sockfd does not refer to a socket.
+ FileDescriptorNotASocket,
+
+ /// The referenced socket is not of type SOCK_STREAM.
+ OperationNotSupported,
+
+ ProtocolFailure,
+
+ /// Firewall rules forbid connection.
+ BlockedByFirewall,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
+ while (true) {
+ var sockaddr_size = u32(@sizeOf(posix.sockaddr));
+ const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EINTR => continue,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
+ posix.EBADF => unreachable, // always a race condition
+ posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
+ posix.ENOBUFS => return PosixAcceptError.SystemResources,
+ posix.ENOMEM => return PosixAcceptError.SystemResources,
+ posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
+ posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
+ posix.EPROTO => return PosixAcceptError.ProtocolFailure,
+ posix.EPERM => return PosixAcceptError.BlockedByFirewall,
+ }
+ }
+}
+
+/// Returns -1 if would block.
+pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
+ while (true) {
+ var sockaddr_size = u32(@sizeOf(posix.sockaddr));
+ const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EINTR => continue,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EAGAIN => return -1,
+ posix.EBADF => unreachable, // always a race condition
+ posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
+ posix.ENOBUFS => return PosixAcceptError.SystemResources,
+ posix.ENOMEM => return PosixAcceptError.SystemResources,
+ posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
+ posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
+ posix.EPROTO => return PosixAcceptError.ProtocolFailure,
+ posix.EPERM => return PosixAcceptError.BlockedByFirewall,
+ }
+ }
+}
+
+pub const LinuxEpollCreateError = error{
+ /// The per-user limit on the number of epoll instances imposed by
+ /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
+ /// details.
+ /// Or, The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
+
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
+
+ /// There was insufficient memory to create the kernel object.
+ SystemResources,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
+ const rc = posix.epoll_create1(flags);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ else => return unexpectedErrorPosix(err),
+
+ posix.EINVAL => unreachable,
+ posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
+ posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
+ }
+}
+
+pub const LinuxEpollCtlError = error{
+ /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
+ /// with this epoll instance.
+ FileDescriptorAlreadyPresentInSet,
+
+ /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
+ /// circular loop of epoll instances monitoring one another.
+ OperationCausesCircularLoop,
+
+ /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
+ /// instance.
+ FileDescriptorNotRegistered,
+
+ /// There was insufficient memory to handle the requested op control operation.
+ SystemResources,
+
+ /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
+ /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
+ /// See epoll(7) for further details.
+ UserResourceLimitReached,
+
+ /// The target file fd does not support epoll. This error can occur if fd refers to,
+ /// for example, a regular file or a directory.
+ FileDescriptorIncompatibleWithEpoll,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
+ const rc = posix.epoll_ctl(epfd, op, fd, event);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EBADF => unreachable, // always a race condition if this happens
+ posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
+ posix.EINVAL => unreachable,
+ posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
+ posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
+ posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
+ posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
+ posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
+ }
+}
+
+pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
+ while (true) {
+ const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return rc,
+ posix.EINTR => continue,
+ posix.EBADF => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ else => unreachable,
+ }
+ }
+}
+
+pub const LinuxEventFdError = error{
+ InvalidFlagValue,
+ SystemResources,
+ ProcessFdQuotaExceeded,
+ SystemFdQuotaExceeded,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
+ const rc = posix.eventfd(initval, flags);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ else => return unexpectedErrorPosix(err),
+
+ posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
+ posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
+ posix.ENODEV => return LinuxEventFdError.SystemResources,
+ posix.ENOMEM => return LinuxEventFdError.SystemResources,
+ }
+}
+
+pub const PosixGetSockNameError = error{
+ /// Insufficient resources were available in the system to perform the operation.
+ SystemResources,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
+ var addr: posix.sockaddr = undefined;
+ var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
+ const rc = posix.getsockname(sockfd, &addr, &addrlen);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return addr,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EBADF => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.ENOTSOCK => unreachable,
+ posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
+ }
+}
+
+pub const PosixConnectError = error{
+ /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
+ /// file, or search permission is denied for one of the directories in the path prefix.
+ /// or
+ /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
+ /// the connection request failed because of a local firewall rule.
+ PermissionDenied,
+
+ /// Local address is already in use.
+ AddressInUse,
+
+ /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
+ /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
+ /// in the ephemeral port range are currently in use. See the discussion of
+ /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
+ AddressNotAvailable,
+
+ /// The passed address didn't have the correct address family in its sa_family field.
+ AddressFamilyNotSupported,
+
+ /// Insufficient entries in the routing cache.
+ SystemResources,
+
+ /// A connect() on a stream socket found no one listening on the remote address.
+ ConnectionRefused,
+
+ /// Network is unreachable.
+ NetworkUnreachable,
+
+ /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
+ /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
+ ConnectionTimedOut,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
+ while (true) {
+ const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EACCES => return PosixConnectError.PermissionDenied,
+ posix.EPERM => return PosixConnectError.PermissionDenied,
+ posix.EADDRINUSE => return PosixConnectError.AddressInUse,
+ posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
+ posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
+ posix.EAGAIN => return PosixConnectError.SystemResources,
+ posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
+ posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
+ posix.EINTR => continue,
+ posix.EISCONN => unreachable, // The socket is already connected.
+ posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
+ posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
+ }
+ }
+}
+
+/// Same as posixConnect except it is for blocking socket file descriptors.
+/// It expects to receive EINPROGRESS.
+pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
+ while (true) {
+ const rc = posix.connect(sockfd, sockaddr, len);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0, posix.EINPROGRESS => return,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EACCES => return PosixConnectError.PermissionDenied,
+ posix.EPERM => return PosixConnectError.PermissionDenied,
+ posix.EADDRINUSE => return PosixConnectError.AddressInUse,
+ posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
+ posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
+ posix.EAGAIN => return PosixConnectError.SystemResources,
+ posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
+ posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ posix.EINTR => continue,
+ posix.EISCONN => unreachable, // The socket is already connected.
+ posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
+ posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
+ }
+ }
+}
+
+pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
+ var err_code: i32 = undefined;
+ var size: u32 = @sizeOf(i32);
+ const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
+ assert(size == 4);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => switch (err_code) {
+ 0 => return,
+ else => return unexpectedErrorPosix(err),
+
+ posix.EACCES => return PosixConnectError.PermissionDenied,
+ posix.EPERM => return PosixConnectError.PermissionDenied,
+ posix.EADDRINUSE => return PosixConnectError.AddressInUse,
+ posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
+ posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
+ posix.EAGAIN => return PosixConnectError.SystemResources,
+ posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
+ posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ posix.EISCONN => unreachable, // The socket is already connected.
+ posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
+ posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
+ },
+ else => return unexpectedErrorPosix(err),
+ posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
+ posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
+ posix.EINVAL => unreachable,
+ posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
+ posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ }
+}
+
+pub const Thread = struct {
+ data: Data,
+
+ pub const use_pthreads = is_posix and builtin.link_libc;
+
+ /// Represents a kernel thread handle.
+ /// May be an integer or a pointer depending on the platform.
+ /// On Linux and POSIX, this is the same as Id.
+ pub const Handle = if (use_pthreads)
+ c.pthread_t
+ else switch (builtin.os) {
+ builtin.Os.linux => i32,
+ builtin.Os.windows => windows.HANDLE,
+ else => @compileError("Unsupported OS"),
+ };
+
+ /// Represents a unique ID per thread.
+ /// May be an integer or pointer depending on the platform.
+ /// On Linux and POSIX, this is the same as Handle.
+ pub const Id = switch (builtin.os) {
+ builtin.Os.windows => windows.DWORD,
+ else => Handle,
+ };
+
+ pub const Data = if (use_pthreads)
+ struct {
+ handle: Thread.Handle,
+ mmap_addr: usize,
+ mmap_len: usize,
+ }
+ else switch (builtin.os) {
+ builtin.Os.linux => struct {
+ handle: Thread.Handle,
+ mmap_addr: usize,
+ mmap_len: usize,
+ tls_end_addr: usize,
+ },
+ builtin.Os.windows => struct {
+ handle: Thread.Handle,
+ alloc_start: *c_void,
+ heap_handle: windows.HANDLE,
+ },
+ else => @compileError("Unsupported OS"),
+ };
+
+ /// Returns the ID of the calling thread.
+ /// Makes a syscall every time the function is called.
+ /// On Linux and POSIX, this Id is the same as a Handle.
+ pub fn getCurrentId() Id {
+ if (use_pthreads) {
+ return c.pthread_self();
+ } else
+ return switch (builtin.os) {
+ builtin.Os.linux => linux.gettid(),
+ builtin.Os.windows => windows.GetCurrentThreadId(),
+ else => @compileError("Unsupported OS"),
+ };
+ }
+
+ /// Returns the handle of this thread.
+ /// On Linux and POSIX, this is the same as Id.
+ pub fn handle(self: Thread) Handle {
+ return self.data.handle;
+ }
+
+ pub fn wait(self: *const Thread) void {
+ if (use_pthreads) {
+ const err = c.pthread_join(self.data.handle, null);
+ switch (err) {
+ 0 => {},
+ posix.EINVAL => unreachable,
+ posix.ESRCH => unreachable,
+ posix.EDEADLK => unreachable,
+ else => unreachable,
+ }
+ assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
+ } else switch (builtin.os) {
+ builtin.Os.linux => {
+ while (true) {
+ const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
+ if (pid_value == 0) break;
+ const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
+ switch (linux.getErrno(rc)) {
+ 0 => continue,
+ posix.EINTR => continue,
+ posix.EAGAIN => continue,
+ else => unreachable,
+ }
+ }
+ assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
+ },
+ builtin.Os.windows => {
+ assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
+ assert(windows.CloseHandle(self.data.handle) != 0);
+ assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
+ },
+ else => @compileError("Unsupported OS"),
+ }
+ }
+};
+
+pub const SpawnThreadError = error{
+ /// A system-imposed limit on the number of threads was encountered.
+ /// There are a number of limits that may trigger this error:
+ /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
+ /// which limits the number of processes and threads for a real
+ /// user ID, was reached;
+ /// * the kernel's system-wide limit on the number of processes and
+ /// threads, /proc/sys/kernel/threads-max, was reached (see
+ /// proc(5));
+ /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
+ /// reached (see proc(5)); or
+ /// * the PID limit (pids.max) imposed by the cgroup "process num‐
+ /// ber" (PIDs) controller was reached.
+ ThreadQuotaExceeded,
+
+ /// The kernel cannot allocate sufficient memory to allocate a task structure
+ /// for the child, or to copy those parts of the caller's context that need to
+ /// be copied.
+ SystemResources,
+
+ /// Not enough userland memory to spawn the thread.
+ OutOfMemory,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub var linux_tls_phdr: ?*std.elf.Phdr = null;
+pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is
+
+/// caller must call wait on the returned thread
+/// fn startFn(@typeOf(context)) T
+/// where T is u8, noreturn, void, or !void
+/// caller must call wait on the returned thread
+pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
+ if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
+ // TODO compile-time call graph analysis to determine stack upper bound
+ // https://github.com/ziglang/zig/issues/157
+ const default_stack_size = 8 * 1024 * 1024;
+
+ const Context = @typeOf(context);
+ comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
+
+ if (builtin.os == builtin.Os.windows) {
+ const WinThread = struct {
+ const OuterContext = struct {
+ thread: Thread,
+ inner: Context,
+ };
+ extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
+ const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
+ switch (@typeId(@typeOf(startFn).ReturnType)) {
+ builtin.TypeId.Int => {
+ return startFn(arg);
+ },
+ builtin.TypeId.Void => {
+ startFn(arg);
+ return 0;
+ },
+ else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
+ }
+ }
+ };
+
+ const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
+ const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
+ const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
+ errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
+ const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
+ const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
+ outer_context.* = WinThread.OuterContext{
+ .thread = Thread{
+ .data = Thread.Data{
+ .heap_handle = heap_handle,
+ .alloc_start = bytes_ptr,
+ .handle = undefined,
+ },
+ },
+ .inner = context,
+ };
+
+ const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
+ outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
+ const err = windows.GetLastError();
+ return switch (err) {
+ else => os.unexpectedErrorWindows(err),
+ };
+ };
+ return &outer_context.thread;
+ }
+
+ const MainFuncs = struct {
+ extern fn linuxThreadMain(ctx_addr: usize) u8 {
+ const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
+
+ switch (@typeId(@typeOf(startFn).ReturnType)) {
+ builtin.TypeId.Int => {
+ return startFn(arg);
+ },
+ builtin.TypeId.Void => {
+ startFn(arg);
+ return 0;
+ },
+ else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
+ }
+ }
+ extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
+ if (@sizeOf(Context) == 0) {
+ _ = startFn({});
+ return null;
+ } else {
+ _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
+ return null;
+ }
+ }
+ };
+
+ const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
+
+ var stack_end_offset: usize = undefined;
+ var thread_start_offset: usize = undefined;
+ var context_start_offset: usize = undefined;
+ var tls_start_offset: usize = undefined;
+ const mmap_len = blk: {
+ // First in memory will be the stack, which grows downwards.
+ var l: usize = mem.alignForward(default_stack_size, os.page_size);
+ stack_end_offset = l;
+ // Above the stack, so that it can be in the same mmap call, put the Thread object.
+ l = mem.alignForward(l, @alignOf(Thread));
+ thread_start_offset = l;
+ l += @sizeOf(Thread);
+ // Next, the Context object.
+ if (@sizeOf(Context) != 0) {
+ l = mem.alignForward(l, @alignOf(Context));
+ context_start_offset = l;
+ l += @sizeOf(Context);
+ }
+ // Finally, the Thread Local Storage, if any.
+ if (!Thread.use_pthreads) {
+ if (linux_tls_phdr) |tls_phdr| {
+ l = mem.alignForward(l, tls_phdr.p_align);
+ tls_start_offset = l;
+ l += tls_phdr.p_memsz;
+ }
+ }
+ break :blk l;
+ };
+ const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
+ if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
+ errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
+
+ const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
+ thread_ptr.data.mmap_addr = mmap_addr;
+ thread_ptr.data.mmap_len = mmap_len;
+
+ var arg: usize = undefined;
+ if (@sizeOf(Context) != 0) {
+ arg = mmap_addr + context_start_offset;
+ const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
+ context_ptr.* = context;
+ }
+
+ if (Thread.use_pthreads) {
+ // use pthreads
+ var attr: c.pthread_attr_t = undefined;
+ if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
+ defer assert(c.pthread_attr_destroy(&attr) == 0);
+
+ assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
+
+ const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
+ switch (err) {
+ 0 => return thread_ptr,
+ posix.EAGAIN => return SpawnThreadError.SystemResources,
+ posix.EPERM => unreachable,
+ posix.EINVAL => unreachable,
+ else => return unexpectedErrorPosix(@intCast(usize, err)),
+ }
+ } else if (builtin.os == builtin.Os.linux) {
+ var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
+ posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
+ posix.CLONE_DETACHED;
+ var newtls: usize = undefined;
+ if (linux_tls_phdr) |tls_phdr| {
+ @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
+ thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
+ newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
+ flags |= posix.CLONE_SETTLS;
+ }
+ const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return thread_ptr,
+ posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
+ posix.EINVAL => unreachable,
+ posix.ENOMEM => return SpawnThreadError.SystemResources,
+ posix.ENOSPC => unreachable,
+ posix.EPERM => unreachable,
+ posix.EUSERS => unreachable,
+ else => return unexpectedErrorPosix(err),
+ }
+ } else {
+ @compileError("Unsupported OS");
+ }
+}
+
+pub fn posixWait(pid: i32) i32 {
+ var status: i32 = undefined;
+ while (true) {
+ const err = posix.getErrno(posix.waitpid(pid, &status, 0));
+ switch (err) {
+ 0 => return status,
+ posix.EINTR => continue,
+ posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
+ posix.EINVAL => unreachable, // The options argument was invalid
+ else => unreachable,
+ }
+ }
+}
+
+pub fn posixFStat(fd: i32) !posix.Stat {
+ var stat: posix.Stat = undefined;
+ const err = posix.getErrno(posix.fstat(fd, &stat));
+ if (err > 0) {
+ return switch (err) {
+ // We do not make this an error code because if you get EBADF it's always a bug,
+ // since the fd could have been reused.
+ posix.EBADF => unreachable,
+ posix.ENOMEM => error.SystemResources,
+ else => os.unexpectedErrorPosix(err),
+ };
+ }
+
+ return stat;
+}
+
+pub const CpuCountError = error{
+ OutOfMemory,
+ PermissionDenied,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
+ switch (builtin.os) {
+ builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
+ var count: c_int = undefined;
+ var count_len: usize = @sizeOf(c_int);
+ const rc = posix.sysctlbyname(switch (builtin.os) {
+ builtin.Os.macosx => c"hw.logicalcpu",
+ else => c"hw.ncpu",
+ }, @ptrCast(*c_void, &count), &count_len, null, 0);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(usize, count),
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.ENOMEM => return CpuCountError.OutOfMemory,
+ posix.ENOTDIR => unreachable,
+ posix.EISDIR => unreachable,
+ posix.ENOENT => unreachable,
+ posix.EPERM => unreachable,
+ else => return os.unexpectedErrorPosix(err),
+ }
+ },
+ builtin.Os.linux => {
+ const usize_count = 16;
+ const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
+
+ var set = try allocator.alloc(usize, usize_count);
+ defer allocator.free(set);
+
+ while (true) {
+ const rc = posix.sched_getaffinity(0, set);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => {
+ if (rc < set.len * @sizeOf(usize)) {
+ const result = set[0 .. rc / @sizeOf(usize)];
+ var sum: usize = 0;
+ for (result) |x| {
+ sum += @popCount(x);
+ }
+ return sum;
+ } else {
+ set = try allocator.realloc(usize, set, set.len * 2);
+ continue;
+ }
+ },
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.EPERM => return CpuCountError.PermissionDenied,
+ posix.ESRCH => unreachable,
+ else => return os.unexpectedErrorPosix(err),
+ }
+ }
+ },
+ builtin.Os.windows => {
+ var system_info: windows.SYSTEM_INFO = undefined;
+ windows.GetSystemInfo(&system_info);
+ return @intCast(usize, system_info.dwNumberOfProcessors);
+ },
+ else => @compileError("unsupported OS"),
+ }
+}
+
+pub const BsdKQueueError = error{
+ /// The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
+
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
+
+ /// See https://github.com/ziglang/zig/issues/1396
+ Unexpected,
+};
+
+pub fn bsdKQueue() BsdKQueueError!i32 {
+ const rc = posix.kqueue();
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
+ posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub const BsdKEventError = error{
+ /// The process does not have permission to register a filter.
+ AccessDenied,
+
+ /// The event could not be found to be modified or deleted.
+ EventNotFound,
+
+ /// No memory was available to register the event.
+ SystemResources,
+
+ /// The specified process to attach to does not exist.
+ ProcessNotFound,
+};
+
+pub fn bsdKEvent(
+ kq: i32,
+ changelist: []const posix.Kevent,
+ eventlist: []posix.Kevent,
+ timeout: ?*const posix.timespec,
+) BsdKEventError!usize {
+ while (true) {
+ const rc = posix.kevent(kq, changelist, eventlist, timeout);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return rc,
+ posix.EACCES => return BsdKEventError.AccessDenied,
+ posix.EFAULT => unreachable,
+ posix.EBADF => unreachable,
+ posix.EINTR => continue,
+ posix.EINVAL => unreachable,
+ posix.ENOENT => return BsdKEventError.EventNotFound,
+ posix.ENOMEM => return BsdKEventError.SystemResources,
+ posix.ESRCH => return BsdKEventError.ProcessNotFound,
+ else => unreachable,
+ }
+ }
+}
+
+pub fn linuxINotifyInit1(flags: u32) !i32 {
+ const rc = linux.inotify_init1(flags);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EINVAL => unreachable,
+ posix.EMFILE => return error.ProcessFdQuotaExceeded,
+ posix.ENFILE => return error.SystemFdQuotaExceeded,
+ posix.ENOMEM => return error.SystemResources,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
+ const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return @intCast(i32, rc),
+ posix.EACCES => return error.AccessDenied,
+ posix.EBADF => unreachable,
+ posix.EFAULT => unreachable,
+ posix.EINVAL => unreachable,
+ posix.ENAMETOOLONG => return error.NameTooLong,
+ posix.ENOENT => return error.FileNotFound,
+ posix.ENOMEM => return error.SystemResources,
+ posix.ENOSPC => return error.UserResourceLimitReached,
+ else => return unexpectedErrorPosix(err),
+ }
+}
+
+pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
+ const rc = linux.inotify_rm_watch(inotify_fd, wd);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return rc,
+ posix.EBADF => unreachable,
+ posix.EINVAL => unreachable,
+ else => unreachable,
+ }
+}
+
+pub const MProtectError = error{
+ AccessDenied,
+ OutOfMemory,
+ Unexpected,
+};
+
+/// address and length must be page-aligned
+pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {
+ const negative_page_size = @bitCast(usize, -isize(page_size));
+ const aligned_address = address & negative_page_size;
+ const aligned_end = (address + length + page_size - 1) & negative_page_size;
+ assert(address == aligned_address);
+ assert(length == aligned_end - aligned_address);
+ const rc = posix.mprotect(address, length, protection);
+ const err = posix.getErrno(rc);
+ switch (err) {
+ 0 => return,
+ posix.EINVAL => unreachable,
+ posix.EACCES => return error.AccessDenied,
+ posix.ENOMEM => return error.OutOfMemory,
+ else => return unexpectedErrorPosix(err),
+ }
+}
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 1da0b3492bcae6e5f8df75900f354eba1c5c31bc..653c77623931d42df5f3b306e5e29c29c5833907 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const cstr = std.cstr;
const unicode = std.unicode;
const io = std.io;
diff --git a/std/os/darwin.zig b/std/os/darwin.zig
index 3e883abbabd52cc2fee19f6797361edcdbf471d0..4ce631c6ab8747202e69841f6786727b0f5ad302 100644
--- a/std/os/darwin.zig
+++ b/std/os/darwin.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const c = std.c;
const assert = std.debug.assert;
const maxInt = std.math.maxInt;
diff --git a/std/os/file.zig b/std/os/file.zig
index 23469a3c3740b445e219ad8ac0b57c6d2fdae6c7..c9a0e2b696d27c219ff5d6741f15f0c15c56900e 100644
--- a/std/os/file.zig
+++ b/std/os/file.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const os = std.os;
const io = std.io;
diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig
new file mode 100644
index 0000000000000000000000000000000000000000..90e8de1557cbf3988b7b69bef82ea634ff690466
--- /dev/null
+++ b/std/os/freebsd.zig
@@ -0,0 +1,845 @@
+const builtin = @import("builtin");
+
+pub use @import("freebsd/errno.zig");
+
+const std = @import("../std.zig");
+const c = std.c;
+
+const assert = std.debug.assert;
+const maxInt = std.math.maxInt;
+pub const Kevent = c.Kevent;
+
+pub const CTL_KERN = 1;
+pub const CTL_DEBUG = 5;
+
+pub const KERN_PROC = 14; // struct: process entries
+pub const KERN_PROC_PATHNAME = 12; // path to executable
+
+pub const PATH_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_VIRTUAL = 1;
+pub const CLOCK_PROF = 2;
+pub const CLOCK_MONOTONIC = 4;
+pub const CLOCK_UPTIME = 5;
+pub const CLOCK_UPTIME_PRECISE = 7;
+pub const CLOCK_UPTIME_FAST = 8;
+pub const CLOCK_REALTIME_PRECISE = 9;
+pub const CLOCK_REALTIME_FAST = 10;
+pub const CLOCK_MONOTONIC_PRECISE = 11;
+pub const CLOCK_MONOTONIC_FAST = 12;
+pub const CLOCK_SECOND = 13;
+pub const CLOCK_THREAD_CPUTIME_ID = 14;
+pub const CLOCK_PROCESS_CPUTIME_ID = 15;
+
+pub const MAP_FAILED = maxInt(usize);
+pub const MAP_SHARED = 0x0001;
+pub const MAP_PRIVATE = 0x0002;
+pub const MAP_FIXED = 0x0010;
+pub const MAP_STACK = 0x0400;
+pub const MAP_NOSYNC = 0x0800;
+pub const MAP_ANON = 0x1000;
+pub const MAP_ANONYMOUS = MAP_ANON;
+pub const MAP_FILE = 0;
+pub const MAP_NORESERVE = 0;
+
+pub const MAP_GUARD = 0x00002000;
+pub const MAP_EXCL = 0x00004000;
+pub const MAP_NOCORE = 0x00020000;
+pub const MAP_PREFAULT_READ = 0x00040000;
+pub const MAP_32BIT = 0x00080000;
+
+pub const WNOHANG = 1;
+pub const WUNTRACED = 2;
+pub const WSTOPPED = WUNTRACED;
+pub const WCONTINUED = 4;
+pub const WNOWAIT = 8;
+pub const WEXITED = 16;
+pub const WTRAPPED = 32;
+
+pub const SA_ONSTACK = 0x0001;
+pub const SA_RESTART = 0x0002;
+pub const SA_RESETHAND = 0x0004;
+pub const SA_NOCLDSTOP = 0x0008;
+pub const SA_NODEFER = 0x0010;
+pub const SA_NOCLDWAIT = 0x0020;
+pub const SA_SIGINFO = 0x0040;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGEMT = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGBUS = 10;
+pub const SIGSEGV = 11;
+pub const SIGSYS = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGURG = 16;
+pub const SIGSTOP = 17;
+pub const SIGTSTP = 18;
+pub const SIGCONT = 19;
+pub const SIGCHLD = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGIO = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGINFO = 29;
+pub const SIGUSR1 = 30;
+pub const SIGUSR2 = 31;
+pub const SIGTHR = 32;
+pub const SIGLWP = SIGTHR;
+pub const SIGLIBRT = 33;
+
+pub const SIGRTMIN = 65;
+pub const SIGRTMAX = 126;
+
+// access function
+pub const F_OK = 0; // test for existence of file
+pub const X_OK = 1; // test for execute or search permission
+pub const W_OK = 2; // test for write permission
+pub const R_OK = 4; // test for read permission
+
+pub const O_RDONLY = 0x0000;
+pub const O_WRONLY = 0x0001;
+pub const O_RDWR = 0x0002;
+pub const O_ACCMODE = 0x0003;
+
+pub const O_CREAT = 0x0200;
+pub const O_EXCL = 0x0800;
+pub const O_NOCTTY = 0x8000;
+pub const O_TRUNC = 0x0400;
+pub const O_APPEND = 0x0008;
+pub const O_NONBLOCK = 0x0004;
+pub const O_DSYNC = 0o10000;
+pub const O_SYNC = 0x0080;
+pub const O_RSYNC = 0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW = 0x0100;
+pub const O_CLOEXEC = 0x00100000;
+
+pub const O_ASYNC = 0x0040;
+pub const O_DIRECT = 0x00010000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0o1000000;
+pub const O_PATH = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 5;
+pub const F_SETLK = 6;
+pub const F_SETLKW = 7;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 1;
+pub const SIG_UNBLOCK = 2;
+pub const SIG_SETMASK = 3;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+
+pub const SOCK_CLOEXEC = 0x10000000;
+pub const SOCK_NONBLOCK = 0x20000000;
+
+pub const PROTO_ip = 0o000;
+pub const PROTO_icmp = 0o001;
+pub const PROTO_igmp = 0o002;
+pub const PROTO_ggp = 0o003;
+pub const PROTO_ipencap = 0o004;
+pub const PROTO_st = 0o005;
+pub const PROTO_tcp = 0o006;
+pub const PROTO_egp = 0o010;
+pub const PROTO_pup = 0o014;
+pub const PROTO_udp = 0o021;
+pub const PROTO_hmp = 0o024;
+pub const PROTO_xns_idp = 0o026;
+pub const PROTO_rdp = 0o033;
+pub const PROTO_iso_tp4 = 0o035;
+pub const PROTO_xtp = 0o044;
+pub const PROTO_ddp = 0o045;
+pub const PROTO_idpr_cmtp = 0o046;
+pub const PROTO_ipv6 = 0o051;
+pub const PROTO_ipv6_route = 0o053;
+pub const PROTO_ipv6_frag = 0o054;
+pub const PROTO_idrp = 0o055;
+pub const PROTO_rsvp = 0o056;
+pub const PROTO_gre = 0o057;
+pub const PROTO_esp = 0o062;
+pub const PROTO_ah = 0o063;
+pub const PROTO_skip = 0o071;
+pub const PROTO_ipv6_icmp = 0o072;
+pub const PROTO_ipv6_nonxt = 0o073;
+pub const PROTO_ipv6_opts = 0o074;
+pub const PROTO_rspf = 0o111;
+pub const PROTO_vmtp = 0o121;
+pub const PROTO_ospf = 0o131;
+pub const PROTO_ipip = 0o136;
+pub const PROTO_encap = 0o142;
+pub const PROTO_pim = 0o147;
+pub const PROTO_raw = 0o377;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_AX25 = 3;
+pub const PF_IPX = 4;
+pub const PF_APPLETALK = 5;
+pub const PF_NETROM = 6;
+pub const PF_BRIDGE = 7;
+pub const PF_ATMPVC = 8;
+pub const PF_X25 = 9;
+pub const PF_INET6 = 10;
+pub const PF_ROSE = 11;
+pub const PF_DECnet = 12;
+pub const PF_NETBEUI = 13;
+pub const PF_SECURITY = 14;
+pub const PF_KEY = 15;
+pub const PF_NETLINK = 16;
+pub const PF_ROUTE = PF_NETLINK;
+pub const PF_PACKET = 17;
+pub const PF_ASH = 18;
+pub const PF_ECONET = 19;
+pub const PF_ATMSVC = 20;
+pub const PF_RDS = 21;
+pub const PF_SNA = 22;
+pub const PF_IRDA = 23;
+pub const PF_PPPOX = 24;
+pub const PF_WANPIPE = 25;
+pub const PF_LLC = 26;
+pub const PF_IB = 27;
+pub const PF_MPLS = 28;
+pub const PF_CAN = 29;
+pub const PF_TIPC = 30;
+pub const PF_BLUETOOTH = 31;
+pub const PF_IUCV = 32;
+pub const PF_RXRPC = 33;
+pub const PF_ISDN = 34;
+pub const PF_PHONET = 35;
+pub const PF_IEEE802154 = 36;
+pub const PF_CAIF = 37;
+pub const PF_ALG = 38;
+pub const PF_NFC = 39;
+pub const PF_VSOCK = 40;
+pub const PF_MAX = 41;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_AX25 = PF_AX25;
+pub const AF_IPX = PF_IPX;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_NETROM = PF_NETROM;
+pub const AF_BRIDGE = PF_BRIDGE;
+pub const AF_ATMPVC = PF_ATMPVC;
+pub const AF_X25 = PF_X25;
+pub const AF_INET6 = PF_INET6;
+pub const AF_ROSE = PF_ROSE;
+pub const AF_DECnet = PF_DECnet;
+pub const AF_NETBEUI = PF_NETBEUI;
+pub const AF_SECURITY = PF_SECURITY;
+pub const AF_KEY = PF_KEY;
+pub const AF_NETLINK = PF_NETLINK;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_PACKET = PF_PACKET;
+pub const AF_ASH = PF_ASH;
+pub const AF_ECONET = PF_ECONET;
+pub const AF_ATMSVC = PF_ATMSVC;
+pub const AF_RDS = PF_RDS;
+pub const AF_SNA = PF_SNA;
+pub const AF_IRDA = PF_IRDA;
+pub const AF_PPPOX = PF_PPPOX;
+pub const AF_WANPIPE = PF_WANPIPE;
+pub const AF_LLC = PF_LLC;
+pub const AF_IB = PF_IB;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_TIPC = PF_TIPC;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_IUCV = PF_IUCV;
+pub const AF_RXRPC = PF_RXRPC;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_PHONET = PF_PHONET;
+pub const AF_IEEE802154 = PF_IEEE802154;
+pub const AF_CAIF = PF_CAIF;
+pub const AF_ALG = PF_ALG;
+pub const AF_NFC = PF_NFC;
+pub const AF_VSOCK = PF_VSOCK;
+pub const AF_MAX = PF_MAX;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
+
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
+
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+pub const EVFILT_READ = -1;
+pub const EVFILT_WRITE = -2;
+
+/// attached to aio requests
+pub const EVFILT_AIO = -3;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = -4;
+
+/// attached to struct proc
+pub const EVFILT_PROC = -5;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = -6;
+
+/// timers
+pub const EVFILT_TIMER = -7;
+
+/// Process descriptors
+pub const EVFILT_PROCDESC = -8;
+
+/// Filesystem events
+pub const EVFILT_FS = -9;
+
+pub const EVFILT_LIO = -10;
+
+/// User events
+pub const EVFILT_USER = -11;
+
+/// Sendfile events
+pub const EVFILT_SENDFILE = -12;
+
+pub const EVFILT_EMPTY = -13;
+
+/// On input, NOTE_TRIGGER causes the event to be triggered for output.
+pub const NOTE_TRIGGER = 0x01000000;
+
+/// ignore input fflags
+pub const NOTE_FFNOP = 0x00000000;
+
+/// and fflags
+pub const NOTE_FFAND = 0x40000000;
+
+/// or fflags
+pub const NOTE_FFOR = 0x80000000;
+
+/// copy fflags
+pub const NOTE_FFCOPY = 0xc0000000;
+
+/// mask for operations
+pub const NOTE_FFCTRLMASK = 0xc0000000;
+pub const NOTE_FFLAGSMASK = 0x00ffffff;
+
+/// low water mark
+pub const NOTE_LOWAT = 0x00000001;
+
+/// behave like poll()
+pub const NOTE_FILE_POLL = 0x00000002;
+
+/// vnode was removed
+pub const NOTE_DELETE = 0x00000001;
+
+/// data contents changed
+pub const NOTE_WRITE = 0x00000002;
+
+/// size increased
+pub const NOTE_EXTEND = 0x00000004;
+
+/// attributes changed
+pub const NOTE_ATTRIB = 0x00000008;
+
+/// link count changed
+pub const NOTE_LINK = 0x00000010;
+
+/// vnode was renamed
+pub const NOTE_RENAME = 0x00000020;
+
+/// vnode access was revoked
+pub const NOTE_REVOKE = 0x00000040;
+
+/// vnode was opened
+pub const NOTE_OPEN = 0x00000080;
+
+/// file closed, fd did not allow write
+pub const NOTE_CLOSE = 0x00000100;
+
+/// file closed, fd did allow write
+pub const NOTE_CLOSE_WRITE = 0x00000200;
+
+/// file was read
+pub const NOTE_READ = 0x00000400;
+
+/// process exited
+pub const NOTE_EXIT = 0x80000000;
+
+/// process forked
+pub const NOTE_FORK = 0x40000000;
+
+/// process exec'd
+pub const NOTE_EXEC = 0x20000000;
+
+/// mask for signal & exit status
+pub const NOTE_PDATAMASK = 0x000fffff;
+pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
+
+/// data is seconds
+pub const NOTE_SECONDS = 0x00000001;
+
+/// data is milliseconds
+pub const NOTE_MSECONDS = 0x00000002;
+
+/// data is microseconds
+pub const NOTE_USECONDS = 0x00000004;
+
+/// data is nanoseconds
+pub const NOTE_NSECONDS = 0x00000008;
+
+/// timeout is absolute
+pub const NOTE_ABSTIME = 0x00000010;
+
+pub const TCGETS = 0x5401;
+pub const TCSETS = 0x5402;
+pub const TCSETSW = 0x5403;
+pub const TCSETSF = 0x5404;
+pub const TCGETA = 0x5405;
+pub const TCSETA = 0x5406;
+pub const TCSETAW = 0x5407;
+pub const TCSETAF = 0x5408;
+pub const TCSBRK = 0x5409;
+pub const TCXONC = 0x540A;
+pub const TCFLSH = 0x540B;
+pub const TIOCEXCL = 0x540C;
+pub const TIOCNXCL = 0x540D;
+pub const TIOCSCTTY = 0x540E;
+pub const TIOCGPGRP = 0x540F;
+pub const TIOCSPGRP = 0x5410;
+pub const TIOCOUTQ = 0x5411;
+pub const TIOCSTI = 0x5412;
+pub const TIOCGWINSZ = 0x5413;
+pub const TIOCSWINSZ = 0x5414;
+pub const TIOCMGET = 0x5415;
+pub const TIOCMBIS = 0x5416;
+pub const TIOCMBIC = 0x5417;
+pub const TIOCMSET = 0x5418;
+pub const TIOCGSOFTCAR = 0x5419;
+pub const TIOCSSOFTCAR = 0x541A;
+pub const FIONREAD = 0x541B;
+pub const TIOCINQ = FIONREAD;
+pub const TIOCLINUX = 0x541C;
+pub const TIOCCONS = 0x541D;
+pub const TIOCGSERIAL = 0x541E;
+pub const TIOCSSERIAL = 0x541F;
+pub const TIOCPKT = 0x5420;
+pub const FIONBIO = 0x5421;
+pub const TIOCNOTTY = 0x5422;
+pub const TIOCSETD = 0x5423;
+pub const TIOCGETD = 0x5424;
+pub const TCSBRKP = 0x5425;
+pub const TIOCSBRK = 0x5427;
+pub const TIOCCBRK = 0x5428;
+pub const TIOCGSID = 0x5429;
+pub const TIOCGRS485 = 0x542E;
+pub const TIOCSRS485 = 0x542F;
+pub const TIOCGPTN = 0x80045430;
+pub const TIOCSPTLCK = 0x40045431;
+pub const TIOCGDEV = 0x80045432;
+pub const TCGETX = 0x5432;
+pub const TCSETX = 0x5433;
+pub const TCSETXF = 0x5434;
+pub const TCSETXW = 0x5435;
+pub const TIOCSIG = 0x40045436;
+pub const TIOCVHANGUP = 0x5437;
+pub const TIOCGPKT = 0x80045438;
+pub const TIOCGPTLCK = 0x80045439;
+pub const TIOCGEXCL = 0x80045440;
+
+pub const sockaddr = c.sockaddr;
+pub const sockaddr_in = c.sockaddr_in;
+pub const sockaddr_in6 = c.sockaddr_in6;
+
+fn unsigned(s: i32) u32 {
+ return @bitCast(u32, s);
+}
+fn signed(s: u32) i32 {
+ return @bitCast(i32, s);
+}
+pub fn WEXITSTATUS(s: i32) i32 {
+ return signed((unsigned(s) & 0xff00) >> 8);
+}
+pub fn WTERMSIG(s: i32) i32 {
+ return signed(unsigned(s) & 0x7f);
+}
+pub fn WSTOPSIG(s: i32) i32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: i32) bool {
+ return WTERMSIG(s) == 0;
+}
+pub fn WIFSTOPPED(s: i32) bool {
+ return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
+}
+pub fn WIFSIGNALED(s: i32) bool {
+ return (unsigned(s) & 0xffff) -% 1 < 0xff;
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+/// Get the errno from a syscall return value, or 0 for no error.
+pub fn getErrno(r: usize) usize {
+ const signed_r = @bitCast(isize, r);
+ return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+}
+
+pub fn dup2(old: i32, new: i32) usize {
+ return errnoWrap(c.dup2(old, new));
+}
+
+pub fn chdir(path: [*]const u8) usize {
+ return errnoWrap(c.chdir(path));
+}
+
+pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
+ return errnoWrap(c.execve(path, argv, envp));
+}
+
+pub fn fork() usize {
+ return errnoWrap(c.fork());
+}
+
+pub fn access(path: [*]const u8, mode: u32) usize {
+ return errnoWrap(c.access(path, mode));
+}
+
+pub fn getcwd(buf: [*]u8, size: usize) usize {
+ return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
+}
+
+pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
+ return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
+}
+
+pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
+ return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
+}
+
+pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
+ return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
+}
+
+pub fn isatty(fd: i32) bool {
+ return c.isatty(fd) != 0;
+}
+
+pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
+ return errnoWrap(c.readlink(path, buf_ptr, buf_len));
+}
+
+pub fn mkdir(path: [*]const u8, mode: u32) usize {
+ return errnoWrap(c.mkdir(path, mode));
+}
+
+pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
+ const ptr_result = c.mmap(
+ @ptrCast(?*c_void, address),
+ length,
+ @bitCast(c_int, @intCast(c_uint, prot)),
+ @bitCast(c_int, c_uint(flags)),
+ fd,
+ offset,
+ );
+ const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
+ return errnoWrap(isize_result);
+}
+
+pub fn munmap(address: usize, length: usize) usize {
+ return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
+}
+
+pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
+ return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
+}
+
+pub fn rmdir(path: [*]const u8) usize {
+ return errnoWrap(c.rmdir(path));
+}
+
+pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
+ return errnoWrap(c.symlink(existing, new));
+}
+
+pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
+ return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
+}
+
+pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
+ return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
+}
+
+pub fn pipe(fd: *[2]i32) usize {
+ return pipe2(fd, 0);
+}
+
+pub fn pipe2(fd: *[2]i32, flags: u32) usize {
+ comptime assert(i32.bit_count == c_int.bit_count);
+ return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
+}
+
+pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
+ return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
+}
+
+pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
+ return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
+}
+
+pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
+ return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
+}
+
+pub fn rename(old: [*]const u8, new: [*]const u8) usize {
+ return errnoWrap(c.rename(old, new));
+}
+
+pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
+ return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
+}
+
+pub fn create(path: [*]const u8, perm: usize) usize {
+ return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
+}
+
+pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
+ return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
+}
+
+pub fn close(fd: i32) usize {
+ return errnoWrap(c.close(fd));
+}
+
+pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
+ return errnoWrap(c.lseek(fd, offset, whence));
+}
+
+pub fn exit(code: i32) noreturn {
+ c.exit(code);
+}
+
+pub fn kill(pid: i32, sig: i32) usize {
+ return errnoWrap(c.kill(pid, sig));
+}
+
+pub fn unlink(path: [*]const u8) usize {
+ return errnoWrap(c.unlink(path));
+}
+
+pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
+ comptime assert(i32.bit_count == c_int.bit_count);
+ return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
+}
+
+pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
+ return errnoWrap(c.nanosleep(req, rem));
+}
+
+pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
+ return errnoWrap(c.clock_gettime(clk_id, tp));
+}
+
+pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
+ return errnoWrap(c.clock_getres(clk_id, tp));
+}
+
+pub fn setuid(uid: u32) usize {
+ return errnoWrap(c.setuid(uid));
+}
+
+pub fn setgid(gid: u32) usize {
+ return errnoWrap(c.setgid(gid));
+}
+
+pub fn setreuid(ruid: u32, euid: u32) usize {
+ return errnoWrap(c.setreuid(ruid, euid));
+}
+
+pub fn setregid(rgid: u32, egid: u32) usize {
+ return errnoWrap(c.setregid(rgid, egid));
+}
+
+const NSIG = 32;
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = extern struct {
+ /// signal handler
+ __sigaction_u: extern union {
+ __sa_handler: extern fn (i32) void,
+ __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
+ },
+
+ /// see signal options
+ sa_flags: u32,
+
+ /// signal mask to apply
+ sa_mask: sigset_t,
+};
+
+pub const _SIG_WORDS = 4;
+pub const _SIG_MAXSIG = 128;
+
+pub inline fn _SIG_IDX(sig: usize) usize {
+ return sig - 1;
+}
+pub inline fn _SIG_WORD(sig: usize) usize {
+ return_SIG_IDX(sig) >> 5;
+}
+pub inline fn _SIG_BIT(sig: usize) usize {
+ return 1 << (_SIG_IDX(sig) & 31);
+}
+pub inline fn _SIG_VALID(sig: usize) usize {
+ return sig <= _SIG_MAXSIG and sig > 0;
+}
+
+pub const sigset_t = extern struct {
+ __bits: [_SIG_WORDS]u32,
+};
+
+pub fn raise(sig: i32) usize {
+ return errnoWrap(c.raise(sig));
+}
+
+pub const Stat = c.Stat;
+pub const dirent = c.dirent;
+pub const timespec = c.timespec;
+
+pub fn fstat(fd: i32, buf: *c.Stat) usize {
+ return errnoWrap(c.fstat(fd, buf));
+}
+pub const iovec = extern struct {
+ iov_base: [*]u8,
+ iov_len: usize,
+};
+
+pub const iovec_const = extern struct {
+ iov_base: [*]const u8,
+ iov_len: usize,
+};
+
+// TODO avoid libc dependency
+pub fn kqueue() usize {
+ return errnoWrap(c.kqueue());
+}
+
+// TODO avoid libc dependency
+pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
+ return errnoWrap(c.kevent(
+ kq,
+ changelist.ptr,
+ @intCast(c_int, changelist.len),
+ eventlist.ptr,
+ @intCast(c_int, eventlist.len),
+ timeout,
+ ));
+}
+
+// TODO avoid libc dependency
+pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
+ return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+}
+
+// TODO avoid libc dependency
+pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
+ return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
+}
+
+// TODO avoid libc dependency
+pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
+ return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
+}
+
+// TODO avoid libc dependency
+
+/// Takes the return value from a syscall and formats it back in the way
+/// that the kernel represents it to libc. Errno was a mistake, let's make
+/// it go away forever.
+fn errnoWrap(value: isize) usize {
+ return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
+}
diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig
deleted file mode 100644
index 48c0ea5b1ea0b26b46e1264e0ff131afe5fef64a..0000000000000000000000000000000000000000
--- a/std/os/freebsd/index.zig
+++ /dev/null
@@ -1,846 +0,0 @@
-const builtin = @import("builtin");
-
-pub use @import("errno.zig");
-
-const std = @import("../../index.zig");
-const c = std.c;
-
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-pub const Kevent = c.Kevent;
-
-pub const CTL_KERN = 1;
-pub const CTL_DEBUG = 5;
-
-pub const KERN_PROC = 14; // struct: process entries
-pub const KERN_PROC_PATHNAME = 12; // path to executable
-
-pub const PATH_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_VIRTUAL = 1;
-pub const CLOCK_PROF = 2;
-pub const CLOCK_MONOTONIC = 4;
-pub const CLOCK_UPTIME = 5;
-pub const CLOCK_UPTIME_PRECISE = 7;
-pub const CLOCK_UPTIME_FAST = 8;
-pub const CLOCK_REALTIME_PRECISE = 9;
-pub const CLOCK_REALTIME_FAST = 10;
-pub const CLOCK_MONOTONIC_PRECISE = 11;
-pub const CLOCK_MONOTONIC_FAST = 12;
-pub const CLOCK_SECOND = 13;
-pub const CLOCK_THREAD_CPUTIME_ID = 14;
-pub const CLOCK_PROCESS_CPUTIME_ID = 15;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x0001;
-pub const MAP_PRIVATE = 0x0002;
-pub const MAP_FIXED = 0x0010;
-pub const MAP_STACK = 0x0400;
-pub const MAP_NOSYNC = 0x0800;
-pub const MAP_ANON = 0x1000;
-pub const MAP_ANONYMOUS = MAP_ANON;
-pub const MAP_FILE = 0;
-pub const MAP_NORESERVE = 0;
-
-pub const MAP_GUARD = 0x00002000;
-pub const MAP_EXCL = 0x00004000;
-pub const MAP_NOCORE = 0x00020000;
-pub const MAP_PREFAULT_READ = 0x00040000;
-pub const MAP_32BIT = 0x00080000;
-
-pub const WNOHANG = 1;
-pub const WUNTRACED = 2;
-pub const WSTOPPED = WUNTRACED;
-pub const WCONTINUED = 4;
-pub const WNOWAIT = 8;
-pub const WEXITED = 16;
-pub const WTRAPPED = 32;
-
-pub const SA_ONSTACK = 0x0001;
-pub const SA_RESTART = 0x0002;
-pub const SA_RESETHAND = 0x0004;
-pub const SA_NOCLDSTOP = 0x0008;
-pub const SA_NODEFER = 0x0010;
-pub const SA_NOCLDWAIT = 0x0020;
-pub const SA_SIGINFO = 0x0040;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGEMT = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGBUS = 10;
-pub const SIGSEGV = 11;
-pub const SIGSYS = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGURG = 16;
-pub const SIGSTOP = 17;
-pub const SIGTSTP = 18;
-pub const SIGCONT = 19;
-pub const SIGCHLD = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGIO = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGINFO = 29;
-pub const SIGUSR1 = 30;
-pub const SIGUSR2 = 31;
-pub const SIGTHR = 32;
-pub const SIGLWP = SIGTHR;
-pub const SIGLIBRT = 33;
-
-pub const SIGRTMIN = 65;
-pub const SIGRTMAX = 126;
-
-// access function
-pub const F_OK = 0; // test for existence of file
-pub const X_OK = 1; // test for execute or search permission
-pub const W_OK = 2; // test for write permission
-pub const R_OK = 4; // test for read permission
-
-
-pub const O_RDONLY = 0x0000;
-pub const O_WRONLY = 0x0001;
-pub const O_RDWR = 0x0002;
-pub const O_ACCMODE = 0x0003;
-
-pub const O_CREAT = 0x0200;
-pub const O_EXCL = 0x0800;
-pub const O_NOCTTY = 0x8000;
-pub const O_TRUNC = 0x0400;
-pub const O_APPEND = 0x0008;
-pub const O_NONBLOCK = 0x0004;
-pub const O_DSYNC = 0o10000;
-pub const O_SYNC = 0x0080;
-pub const O_RSYNC = 0o4010000;
-pub const O_DIRECTORY = 0o200000;
-pub const O_NOFOLLOW = 0x0100;
-pub const O_CLOEXEC = 0x00100000;
-
-pub const O_ASYNC = 0x0040;
-pub const O_DIRECT = 0x00010000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0o1000000;
-pub const O_PATH = 0o10000000;
-pub const O_TMPFILE = 0o20200000;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_SETOWN = 8;
-pub const F_GETOWN = 9;
-pub const F_SETSIG = 10;
-pub const F_GETSIG = 11;
-
-pub const F_GETLK = 5;
-pub const F_SETLK = 6;
-pub const F_SETLKW = 7;
-
-pub const F_SETOWN_EX = 15;
-pub const F_GETOWN_EX = 16;
-
-pub const F_GETOWNER_UIDS = 17;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 1;
-pub const SIG_UNBLOCK = 2;
-pub const SIG_SETMASK = 3;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-
-pub const SOCK_CLOEXEC = 0x10000000;
-pub const SOCK_NONBLOCK = 0x20000000;
-
-pub const PROTO_ip = 0o000;
-pub const PROTO_icmp = 0o001;
-pub const PROTO_igmp = 0o002;
-pub const PROTO_ggp = 0o003;
-pub const PROTO_ipencap = 0o004;
-pub const PROTO_st = 0o005;
-pub const PROTO_tcp = 0o006;
-pub const PROTO_egp = 0o010;
-pub const PROTO_pup = 0o014;
-pub const PROTO_udp = 0o021;
-pub const PROTO_hmp = 0o024;
-pub const PROTO_xns_idp = 0o026;
-pub const PROTO_rdp = 0o033;
-pub const PROTO_iso_tp4 = 0o035;
-pub const PROTO_xtp = 0o044;
-pub const PROTO_ddp = 0o045;
-pub const PROTO_idpr_cmtp = 0o046;
-pub const PROTO_ipv6 = 0o051;
-pub const PROTO_ipv6_route = 0o053;
-pub const PROTO_ipv6_frag = 0o054;
-pub const PROTO_idrp = 0o055;
-pub const PROTO_rsvp = 0o056;
-pub const PROTO_gre = 0o057;
-pub const PROTO_esp = 0o062;
-pub const PROTO_ah = 0o063;
-pub const PROTO_skip = 0o071;
-pub const PROTO_ipv6_icmp = 0o072;
-pub const PROTO_ipv6_nonxt = 0o073;
-pub const PROTO_ipv6_opts = 0o074;
-pub const PROTO_rspf = 0o111;
-pub const PROTO_vmtp = 0o121;
-pub const PROTO_ospf = 0o131;
-pub const PROTO_ipip = 0o136;
-pub const PROTO_encap = 0o142;
-pub const PROTO_pim = 0o147;
-pub const PROTO_raw = 0o377;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_AX25 = 3;
-pub const PF_IPX = 4;
-pub const PF_APPLETALK = 5;
-pub const PF_NETROM = 6;
-pub const PF_BRIDGE = 7;
-pub const PF_ATMPVC = 8;
-pub const PF_X25 = 9;
-pub const PF_INET6 = 10;
-pub const PF_ROSE = 11;
-pub const PF_DECnet = 12;
-pub const PF_NETBEUI = 13;
-pub const PF_SECURITY = 14;
-pub const PF_KEY = 15;
-pub const PF_NETLINK = 16;
-pub const PF_ROUTE = PF_NETLINK;
-pub const PF_PACKET = 17;
-pub const PF_ASH = 18;
-pub const PF_ECONET = 19;
-pub const PF_ATMSVC = 20;
-pub const PF_RDS = 21;
-pub const PF_SNA = 22;
-pub const PF_IRDA = 23;
-pub const PF_PPPOX = 24;
-pub const PF_WANPIPE = 25;
-pub const PF_LLC = 26;
-pub const PF_IB = 27;
-pub const PF_MPLS = 28;
-pub const PF_CAN = 29;
-pub const PF_TIPC = 30;
-pub const PF_BLUETOOTH = 31;
-pub const PF_IUCV = 32;
-pub const PF_RXRPC = 33;
-pub const PF_ISDN = 34;
-pub const PF_PHONET = 35;
-pub const PF_IEEE802154 = 36;
-pub const PF_CAIF = 37;
-pub const PF_ALG = 38;
-pub const PF_NFC = 39;
-pub const PF_VSOCK = 40;
-pub const PF_MAX = 41;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_AX25 = PF_AX25;
-pub const AF_IPX = PF_IPX;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_NETROM = PF_NETROM;
-pub const AF_BRIDGE = PF_BRIDGE;
-pub const AF_ATMPVC = PF_ATMPVC;
-pub const AF_X25 = PF_X25;
-pub const AF_INET6 = PF_INET6;
-pub const AF_ROSE = PF_ROSE;
-pub const AF_DECnet = PF_DECnet;
-pub const AF_NETBEUI = PF_NETBEUI;
-pub const AF_SECURITY = PF_SECURITY;
-pub const AF_KEY = PF_KEY;
-pub const AF_NETLINK = PF_NETLINK;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_PACKET = PF_PACKET;
-pub const AF_ASH = PF_ASH;
-pub const AF_ECONET = PF_ECONET;
-pub const AF_ATMSVC = PF_ATMSVC;
-pub const AF_RDS = PF_RDS;
-pub const AF_SNA = PF_SNA;
-pub const AF_IRDA = PF_IRDA;
-pub const AF_PPPOX = PF_PPPOX;
-pub const AF_WANPIPE = PF_WANPIPE;
-pub const AF_LLC = PF_LLC;
-pub const AF_IB = PF_IB;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_TIPC = PF_TIPC;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_IUCV = PF_IUCV;
-pub const AF_RXRPC = PF_RXRPC;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_PHONET = PF_PHONET;
-pub const AF_IEEE802154 = PF_IEEE802154;
-pub const AF_CAIF = PF_CAIF;
-pub const AF_ALG = PF_ALG;
-pub const AF_NFC = PF_NFC;
-pub const AF_VSOCK = PF_VSOCK;
-pub const AF_MAX = PF_MAX;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-pub const EVFILT_READ = -1;
-pub const EVFILT_WRITE = -2;
-
-/// attached to aio requests
-pub const EVFILT_AIO = -3;
-
-/// attached to vnodes
-pub const EVFILT_VNODE = -4;
-
-/// attached to struct proc
-pub const EVFILT_PROC = -5;
-
-/// attached to struct proc
-pub const EVFILT_SIGNAL = -6;
-
-/// timers
-pub const EVFILT_TIMER = -7;
-
-/// Process descriptors
-pub const EVFILT_PROCDESC = -8;
-
-/// Filesystem events
-pub const EVFILT_FS = -9;
-
-pub const EVFILT_LIO = -10;
-
-/// User events
-pub const EVFILT_USER = -11;
-
-/// Sendfile events
-pub const EVFILT_SENDFILE = -12;
-
-pub const EVFILT_EMPTY = -13;
-
-/// On input, NOTE_TRIGGER causes the event to be triggered for output.
-pub const NOTE_TRIGGER = 0x01000000;
-
-/// ignore input fflags
-pub const NOTE_FFNOP = 0x00000000;
-
-/// and fflags
-pub const NOTE_FFAND = 0x40000000;
-
-/// or fflags
-pub const NOTE_FFOR = 0x80000000;
-
-/// copy fflags
-pub const NOTE_FFCOPY = 0xc0000000;
-
-/// mask for operations
-pub const NOTE_FFCTRLMASK = 0xc0000000;
-pub const NOTE_FFLAGSMASK = 0x00ffffff;
-
-/// low water mark
-pub const NOTE_LOWAT = 0x00000001;
-
-/// behave like poll()
-pub const NOTE_FILE_POLL = 0x00000002;
-
-/// vnode was removed
-pub const NOTE_DELETE = 0x00000001;
-
-/// data contents changed
-pub const NOTE_WRITE = 0x00000002;
-
-/// size increased
-pub const NOTE_EXTEND = 0x00000004;
-
-/// attributes changed
-pub const NOTE_ATTRIB = 0x00000008;
-
-/// link count changed
-pub const NOTE_LINK = 0x00000010;
-
-/// vnode was renamed
-pub const NOTE_RENAME = 0x00000020;
-
-/// vnode access was revoked
-pub const NOTE_REVOKE = 0x00000040;
-
-/// vnode was opened
-pub const NOTE_OPEN = 0x00000080;
-
-/// file closed, fd did not allow write
-pub const NOTE_CLOSE = 0x00000100;
-
-/// file closed, fd did allow write
-pub const NOTE_CLOSE_WRITE = 0x00000200;
-
-/// file was read
-pub const NOTE_READ = 0x00000400;
-
-/// process exited
-pub const NOTE_EXIT = 0x80000000;
-
-/// process forked
-pub const NOTE_FORK = 0x40000000;
-
-/// process exec'd
-pub const NOTE_EXEC = 0x20000000;
-
-/// mask for signal & exit status
-pub const NOTE_PDATAMASK = 0x000fffff;
-pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
-
-/// data is seconds
-pub const NOTE_SECONDS = 0x00000001;
-
-/// data is milliseconds
-pub const NOTE_MSECONDS = 0x00000002;
-
-/// data is microseconds
-pub const NOTE_USECONDS = 0x00000004;
-
-/// data is nanoseconds
-pub const NOTE_NSECONDS = 0x00000008;
-
-/// timeout is absolute
-pub const NOTE_ABSTIME = 0x00000010;
-
-pub const TCGETS = 0x5401;
-pub const TCSETS = 0x5402;
-pub const TCSETSW = 0x5403;
-pub const TCSETSF = 0x5404;
-pub const TCGETA = 0x5405;
-pub const TCSETA = 0x5406;
-pub const TCSETAW = 0x5407;
-pub const TCSETAF = 0x5408;
-pub const TCSBRK = 0x5409;
-pub const TCXONC = 0x540A;
-pub const TCFLSH = 0x540B;
-pub const TIOCEXCL = 0x540C;
-pub const TIOCNXCL = 0x540D;
-pub const TIOCSCTTY = 0x540E;
-pub const TIOCGPGRP = 0x540F;
-pub const TIOCSPGRP = 0x5410;
-pub const TIOCOUTQ = 0x5411;
-pub const TIOCSTI = 0x5412;
-pub const TIOCGWINSZ = 0x5413;
-pub const TIOCSWINSZ = 0x5414;
-pub const TIOCMGET = 0x5415;
-pub const TIOCMBIS = 0x5416;
-pub const TIOCMBIC = 0x5417;
-pub const TIOCMSET = 0x5418;
-pub const TIOCGSOFTCAR = 0x5419;
-pub const TIOCSSOFTCAR = 0x541A;
-pub const FIONREAD = 0x541B;
-pub const TIOCINQ = FIONREAD;
-pub const TIOCLINUX = 0x541C;
-pub const TIOCCONS = 0x541D;
-pub const TIOCGSERIAL = 0x541E;
-pub const TIOCSSERIAL = 0x541F;
-pub const TIOCPKT = 0x5420;
-pub const FIONBIO = 0x5421;
-pub const TIOCNOTTY = 0x5422;
-pub const TIOCSETD = 0x5423;
-pub const TIOCGETD = 0x5424;
-pub const TCSBRKP = 0x5425;
-pub const TIOCSBRK = 0x5427;
-pub const TIOCCBRK = 0x5428;
-pub const TIOCGSID = 0x5429;
-pub const TIOCGRS485 = 0x542E;
-pub const TIOCSRS485 = 0x542F;
-pub const TIOCGPTN = 0x80045430;
-pub const TIOCSPTLCK = 0x40045431;
-pub const TIOCGDEV = 0x80045432;
-pub const TCGETX = 0x5432;
-pub const TCSETX = 0x5433;
-pub const TCSETXF = 0x5434;
-pub const TCSETXW = 0x5435;
-pub const TIOCSIG = 0x40045436;
-pub const TIOCVHANGUP = 0x5437;
-pub const TIOCGPKT = 0x80045438;
-pub const TIOCGPTLCK = 0x80045439;
-pub const TIOCGEXCL = 0x80045440;
-
-pub const sockaddr = c.sockaddr;
-pub const sockaddr_in = c.sockaddr_in;
-pub const sockaddr_in6 = c.sockaddr_in6;
-
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) & 0xff00) >> 8);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-pub fn WIFSTOPPED(s: i32) bool {
- return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
-}
-pub fn WIFSIGNALED(s: i32) bool {
- return (unsigned(s) & 0xffff) -% 1 < 0xff;
-}
-
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return errnoWrap(c.dup2(old, new));
-}
-
-pub fn chdir(path: [*]const u8) usize {
- return errnoWrap(c.chdir(path));
-}
-
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return errnoWrap(c.execve(path, argv, envp));
-}
-
-pub fn fork() usize {
- return errnoWrap(c.fork());
-}
-
-pub fn access(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.access(path, mode));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
- return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
-}
-
-pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
- return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
-}
-
-pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
- return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn isatty(fd: i32) bool {
- return c.isatty(fd) != 0;
-}
-
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return errnoWrap(c.readlink(path, buf_ptr, buf_len));
-}
-
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.mkdir(path, mode));
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- const ptr_result = c.mmap(
- @ptrCast(?*c_void, address),
- length,
- @bitCast(c_int, @intCast(c_uint, prot)),
- @bitCast(c_int, c_uint(flags)),
- fd,
- offset,
- );
- const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
- return errnoWrap(isize_result);
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
-}
-
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
-}
-
-pub fn rmdir(path: [*]const u8) usize {
- return errnoWrap(c.rmdir(path));
-}
-
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.symlink(existing, new));
-}
-
-pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
-}
-
-pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
- return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
-}
-
-pub fn pipe2(fd: *[2]i32, flags: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
-}
-
-pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
- return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
-}
-
-pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
- return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.rename(old, new));
-}
-
-pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
- return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
-}
-
-pub fn create(path: [*]const u8, perm: usize) usize {
- return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
-}
-
-pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
- return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
-}
-
-pub fn close(fd: i32) usize {
- return errnoWrap(c.close(fd));
-}
-
-pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
- return errnoWrap(c.lseek(fd, offset, whence));
-}
-
-pub fn exit(code: i32) noreturn {
- c.exit(code);
-}
-
-pub fn kill(pid: i32, sig: i32) usize {
- return errnoWrap(c.kill(pid, sig));
-}
-
-pub fn unlink(path: [*]const u8) usize {
- return errnoWrap(c.unlink(path));
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return errnoWrap(c.nanosleep(req, rem));
-}
-
-pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_gettime(clk_id, tp));
-}
-
-pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_getres(clk_id, tp));
-}
-
-pub fn setuid(uid: u32) usize {
- return errnoWrap(c.setuid(uid));
-}
-
-pub fn setgid(gid: u32) usize {
- return errnoWrap(c.setgid(gid));
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return errnoWrap(c.setreuid(ruid, euid));
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return errnoWrap(c.setregid(rgid, egid));
-}
-
-const NSIG = 32;
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = extern struct {
- /// signal handler
- __sigaction_u: extern union {
- __sa_handler: extern fn (i32) void,
- __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
- },
-
- /// see signal options
- sa_flags: u32,
-
- /// signal mask to apply
- sa_mask: sigset_t,
-};
-
-pub const _SIG_WORDS = 4;
-pub const _SIG_MAXSIG = 128;
-
-pub inline fn _SIG_IDX(sig: usize) usize {
- return sig - 1;
-}
-pub inline fn _SIG_WORD(sig: usize) usize {
- return_SIG_IDX(sig) >> 5;
-}
-pub inline fn _SIG_BIT(sig: usize) usize {
- return 1 << (_SIG_IDX(sig) & 31);
-}
-pub inline fn _SIG_VALID(sig: usize) usize {
- return sig <= _SIG_MAXSIG and sig > 0;
-}
-
-pub const sigset_t = extern struct {
- __bits: [_SIG_WORDS]u32,
-};
-
-pub fn raise(sig: i32) usize {
- return errnoWrap(c.raise(sig));
-}
-
-pub const Stat = c.Stat;
-pub const dirent = c.dirent;
-pub const timespec = c.timespec;
-
-pub fn fstat(fd: i32, buf: *c.Stat) usize {
- return errnoWrap(c.fstat(fd, buf));
-}
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-// TODO avoid libc dependency
-pub fn kqueue() usize {
- return errnoWrap(c.kqueue());
-}
-
-// TODO avoid libc dependency
-pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
- return errnoWrap(c.kevent(
- kq,
- changelist.ptr,
- @intCast(c_int, changelist.len),
- eventlist.ptr,
- @intCast(c_int, eventlist.len),
- timeout,
- ));
-}
-
-// TODO avoid libc dependency
-pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
- return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
-}
-
-// TODO avoid libc dependency
-
-/// Takes the return value from a syscall and formats it back in the way
-/// that the kernel represents it to libc. Errno was a mistake, let's make
-/// it go away forever.
-fn errnoWrap(value: isize) usize {
- return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
-}
diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig
index a49d164f4621ccc1e9be6f78bc22cbc3379ad69a..e69c03edb94fb0021df4418248700eacd6ad2c81 100644
--- a/std/os/get_app_data_dir.zig
+++ b/std/os/get_app_data_dir.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const unicode = std.unicode;
const mem = std.mem;
diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig
index 6747cc455790f56a5236ca674d031bd769402075..db44c6838fd5cfa2396d39172fe109bb31321ae5 100644
--- a/std/os/get_user_id.zig
+++ b/std/os/get_user_id.zig
@@ -1,6 +1,6 @@
const builtin = @import("builtin");
const Os = builtin.Os;
-const os = @import("index.zig");
+const os = @import("../os.zig");
const io = @import("../io.zig");
pub const UserInfo = struct {
diff --git a/std/os/index.zig b/std/os/index.zig
deleted file mode 100644
index 148f4ebe064c4dd053f6273dadde9c41039c4242..0000000000000000000000000000000000000000
--- a/std/os/index.zig
+++ /dev/null
@@ -1,3408 +0,0 @@
-const std = @import("../index.zig");
-const builtin = @import("builtin");
-const Os = builtin.Os;
-const is_windows = builtin.os == Os.windows;
-const is_posix = switch (builtin.os) {
- builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
- else => false,
-};
-const os = @This();
-
-comptime {
- assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
-}
-
-test "std.os" {
- _ = @import("child_process.zig");
- _ = @import("darwin.zig");
- _ = @import("darwin/errno.zig");
- _ = @import("get_user_id.zig");
- _ = @import("linux/index.zig");
- _ = @import("path.zig");
- _ = @import("test.zig");
- _ = @import("time.zig");
- _ = @import("windows/index.zig");
- _ = @import("uefi.zig");
- _ = @import("get_app_data_dir.zig");
-}
-
-pub const windows = @import("windows/index.zig");
-pub const darwin = @import("darwin.zig");
-pub const linux = @import("linux/index.zig");
-pub const freebsd = @import("freebsd/index.zig");
-pub const netbsd = @import("netbsd/index.zig");
-pub const zen = @import("zen.zig");
-pub const uefi = @import("uefi.zig");
-
-pub const posix = switch (builtin.os) {
- Os.linux => linux,
- Os.macosx, Os.ios => darwin,
- Os.freebsd => freebsd,
- Os.netbsd => netbsd,
- Os.zen => zen,
- else => @compileError("Unsupported OS"),
-};
-
-pub const net = @import("net.zig");
-
-pub const ChildProcess = @import("child_process.zig").ChildProcess;
-pub const path = @import("path.zig");
-pub const File = @import("file.zig").File;
-pub const time = @import("time.zig");
-
-pub const page_size = 4 * 1024;
-pub const MAX_PATH_BYTES = switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
- // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
- // If it would require 4 UTF-8 bytes, then there would be a surrogate
- // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
- // +1 for the null byte at the end, which can be encoded in 1 byte.
- Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
- else => @compileError("Unsupported OS"),
-};
-
-pub const UserInfo = @import("get_user_id.zig").UserInfo;
-pub const getUserInfo = @import("get_user_id.zig").getUserInfo;
-
-const windows_util = @import("windows/util.zig");
-pub const windowsWaitSingle = windows_util.windowsWaitSingle;
-pub const windowsWrite = windows_util.windowsWrite;
-pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
-pub const windowsOpen = windows_util.windowsOpen;
-pub const windowsOpenW = windows_util.windowsOpenW;
-pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
-
-pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
-pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
-
-pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
-pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
-
-pub const WindowsWaitResult = windows_util.WindowsWaitResult;
-pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
-
-pub const WindowsWaitError = windows_util.WaitError;
-pub const WindowsOpenError = windows_util.OpenError;
-pub const WindowsWriteError = windows_util.WriteError;
-pub const WindowsReadError = windows_util.ReadError;
-
-pub const FileHandle = if (is_windows) windows.HANDLE else i32;
-
-pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
-pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
-
-const debug = std.debug;
-const assert = debug.assert;
-const testing = std.testing;
-
-const c = std.c;
-
-const mem = std.mem;
-const Allocator = mem.Allocator;
-
-const BufMap = std.BufMap;
-const cstr = std.cstr;
-
-const io = std.io;
-const base64 = std.base64;
-const ArrayList = std.ArrayList;
-const Buffer = std.Buffer;
-const math = std.math;
-
-/// Fills `buf` with random bytes. If linking against libc, this calls the
-/// appropriate OS-specific library call. Otherwise it uses the zig standard
-/// library implementation.
-pub fn getRandomBytes(buf: []u8) !void {
- switch (builtin.os) {
- Os.linux => while (true) {
- // TODO check libc version and potentially call c.getrandom.
- // See #397
- const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
- switch (errno) {
- 0 => return,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EINTR => continue,
- posix.ENOSYS => return getRandomBytesDevURandom(buf),
- else => return unexpectedErrorPosix(errno),
- }
- },
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
- Os.windows => {
- // Call RtlGenRandom() instead of CryptGetRandom() on Windows
- // https://github.com/rust-lang-nursery/rand/issues/111
- // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
- if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => unexpectedErrorWindows(err),
- };
- }
- },
- Os.zen => {
- const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
- var i: usize = 0;
- while (i < buf.len) : (i += 1) {
- if (i > randomness.len) return error.Unknown;
- buf[i] = randomness[i];
- }
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-fn getRandomBytesDevURandom(buf: []u8) !void {
- const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
- defer close(fd);
-
- const stream = &File.openHandle(fd).inStream().stream;
- stream.readNoEof(buf) catch |err| switch (err) {
- error.EndOfStream => unreachable,
- error.OperationAborted => unreachable,
- error.BrokenPipe => unreachable,
- error.Unexpected => return error.Unexpected,
- error.InputOutput => return error.Unexpected,
- error.SystemResources => return error.Unexpected,
- error.IsDir => unreachable,
- };
-}
-
-test "os.getRandomBytes" {
- var buf_a: [50]u8 = undefined;
- var buf_b: [50]u8 = undefined;
- // Call Twice
- try getRandomBytes(buf_a[0..]);
- try getRandomBytes(buf_b[0..]);
-
- // Check if random (not 100% conclusive)
- testing.expect(!mem.eql(u8, buf_a, buf_b));
-}
-
-/// Raises a signal in the current kernel thread, ending its execution.
-/// If linking against libc, this calls the abort() libc function. Otherwise
-/// it uses the zig standard library implementation.
-pub fn abort() noreturn {
- @setCold(true);
- if (builtin.link_libc) {
- c.abort();
- }
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- _ = posix.raise(posix.SIGABRT);
- _ = posix.raise(posix.SIGKILL);
- while (true) {}
- },
- Os.windows => {
- if (builtin.mode == builtin.Mode.Debug) {
- @breakpoint();
- }
- windows.ExitProcess(3);
- },
- Os.uefi => {
- // TODO there's gotta be a better thing to do here than loop forever
- while (true) {}
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// Exits the program cleanly with the specified status code.
-pub fn exit(status: u8) noreturn {
- @setCold(true);
- if (builtin.link_libc) {
- c.exit(status);
- }
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- posix.exit(status);
- },
- Os.windows => {
- windows.ExitProcess(status);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// When a file descriptor is closed on linux, it pops the first
-/// node from this queue and resumes it.
-/// Async functions which get the EMFILE error code can suspend,
-/// putting their coroutine handle into this list.
-/// TODO make this an atomic linked list
-pub var emfile_promise_queue = std.LinkedList(promise).init();
-
-/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
-pub fn close(handle: FileHandle) void {
- if (is_windows) {
- windows_util.windowsClose(handle);
- } else {
- while (true) {
- const err = posix.getErrno(posix.close(handle));
- switch (err) {
- posix.EINTR => continue,
- else => {
- if (emfile_promise_queue.popFirst()) |p| resume p.data;
- return;
- },
- }
- }
- }
-}
-
-pub const PosixReadError = error{
- InputOutput,
- SystemResources,
- IsDir,
- Unexpected,
-};
-
-/// Returns the number of bytes that were read, which can be less than
-/// buf.len. If 0 bytes were read, that means EOF.
-pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
- // Linux can return EINVAL when read amount is > 0x7ffff000
- // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
- const max_buf_len = 0x7ffff000;
-
- var index: usize = 0;
- while (index < buf.len) {
- const want_to_read = math.min(buf.len - index, usize(max_buf_len));
- const rc = posix.read(fd, buf.ptr + index, want_to_read);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => {
- index += rc;
- if (rc == want_to_read) continue;
- // Read returned less than buf.len.
- return index;
- },
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable,
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
- }
- }
- return index;
-}
-
-/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
-pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
- switch (builtin.os) {
- builtin.Os.macosx => {
- // Darwin does not have preadv but it does have pread.
- var off: usize = 0;
- var iov_i: usize = 0;
- var inner_off: usize = 0;
- while (true) {
- const v = iov[iov_i];
- const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
- const err = darwin.getErrno(rc);
- switch (err) {
- 0 => {
- off += rc;
- inner_off += rc;
- if (inner_off == v.iov_len) {
- iov_i += 1;
- inner_off = 0;
- if (iov_i == count) {
- return off;
- }
- }
- if (rc == 0) return off; // EOF
- continue;
- },
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.ESPIPE => unreachable, // fd is not seekable
- posix.EAGAIN => unreachable, // this function is not for non blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
- const rc = posix.preadv(fd, iov, count, offset);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // don't call this function for non blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
- }
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-pub const PosixWriteError = error{
- DiskQuota,
- FileTooBig,
- InputOutput,
- NoSpaceLeft,
- AccessDenied,
- BrokenPipe,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-/// Calls POSIX write, and keeps trying if it gets interrupted.
-pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
- // Linux can return EINVAL when write amount is > 0x7ffff000
- // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
- const max_bytes_len = 0x7ffff000;
-
- var index: usize = 0;
- while (index < bytes.len) {
- const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
- const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
- const write_err = posix.getErrno(rc);
- switch (write_err) {
- 0 => {
- index += rc;
- continue;
- },
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(write_err),
- }
- }
-}
-
-pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
- switch (builtin.os) {
- builtin.Os.macosx => {
- // Darwin does not have pwritev but it does have pwrite.
- var off: usize = 0;
- var iov_i: usize = 0;
- var inner_off: usize = 0;
- while (true) {
- const v = iov[iov_i];
- const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
- const err = darwin.getErrno(rc);
- switch (err) {
- 0 => {
- off += rc;
- inner_off += rc;
- if (inner_off == v.iov_len) {
- iov_i += 1;
- inner_off = 0;
- if (iov_i == count) {
- return;
- }
- }
- continue;
- },
- posix.EINTR => continue,
- posix.ESPIPE => unreachable, // fd is not seekable
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
- const rc = posix.pwritev(fd, iov, count, offset);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(err),
- }
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-pub const PosixOpenError = error{
- AccessDenied,
- FileTooBig,
- IsDir,
- SymLinkLoop,
- ProcessFdQuotaExceeded,
- NameTooLong,
- SystemFdQuotaExceeded,
- NoDevice,
- FileNotFound,
- SystemResources,
- NoSpaceLeft,
- NotDir,
- PathAlreadyExists,
- DeviceBusy,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-/// ::file_path needs to be copied in memory to add a null terminating byte.
-/// Calls POSIX open, keeps trying if it gets interrupted, and translates
-/// the return value into zig errors.
-pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
- const file_path_c = try toPosixPath(file_path);
- return posixOpenC(&file_path_c, flags, perm);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
- while (true) {
- const result = posix.open(file_path, flags, perm);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EINTR => continue,
-
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EACCES => return PosixOpenError.AccessDenied,
- posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
- posix.EISDIR => return PosixOpenError.IsDir,
- posix.ELOOP => return PosixOpenError.SymLinkLoop,
- posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
- posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
- posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
- posix.ENODEV => return PosixOpenError.NoDevice,
- posix.ENOENT => return PosixOpenError.FileNotFound,
- posix.ENOMEM => return PosixOpenError.SystemResources,
- posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
- posix.ENOTDIR => return PosixOpenError.NotDir,
- posix.EPERM => return PosixOpenError.AccessDenied,
- posix.EEXIST => return PosixOpenError.PathAlreadyExists,
- posix.EBUSY => return PosixOpenError.DeviceBusy,
- else => return unexpectedErrorPosix(err),
- }
- }
- return @intCast(i32, result);
- }
-}
-
-/// Used to convert a slice to a null terminated slice on the stack.
-/// TODO well defined copy elision
-pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
- var path_with_null: [posix.PATH_MAX]u8 = undefined;
- if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
- mem.copy(u8, path_with_null[0..], file_path);
- path_with_null[file_path.len] = 0;
- return path_with_null;
-}
-
-pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
- while (true) {
- const err = posix.getErrno(posix.dup2(old_fd, new_fd));
- if (err > 0) {
- return switch (err) {
- posix.EBUSY, posix.EINTR => continue,
- posix.EMFILE => error.ProcessFdQuotaExceeded,
- posix.EINVAL => unreachable,
- else => unexpectedErrorPosix(err),
- };
- }
- return;
- }
-}
-
-pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
- const envp_count = env_map.count();
- const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
- mem.set(?[*]u8, envp_buf, null);
- errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
- {
- var it = env_map.iterator();
- var i: usize = 0;
- while (it.next()) |pair| : (i += 1) {
- const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
- @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
- env_buf[pair.key.len] = '=';
- @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
- env_buf[env_buf.len - 1] = 0;
-
- envp_buf[i] = env_buf.ptr;
- }
- assert(i == envp_count);
- }
- assert(envp_buf[envp_count] == null);
- return envp_buf;
-}
-
-pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
- for (envp_buf) |env| {
- const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
- allocator.free(env_buf);
- }
- allocator.free(envp_buf);
-}
-
-/// This function must allocate memory to add a null terminating bytes on path and each arg.
-/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
-/// pointers after the args and after the environment variables.
-/// `argv[0]` is the executable path.
-/// This function also uses the PATH environment variable to get the full path to the executable.
-pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
- const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
- mem.set(?[*]u8, argv_buf, null);
- defer {
- for (argv_buf) |arg| {
- const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
- allocator.free(arg_buf);
- }
- allocator.free(argv_buf);
- }
- for (argv) |arg, i| {
- const arg_buf = try allocator.alloc(u8, arg.len + 1);
- @memcpy(arg_buf.ptr, arg.ptr, arg.len);
- arg_buf[arg.len] = 0;
-
- argv_buf[i] = arg_buf.ptr;
- }
- argv_buf[argv.len] = null;
-
- const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
- defer freeNullDelimitedEnvMap(allocator, envp_buf);
-
- const exe_path = argv[0];
- if (mem.indexOfScalar(u8, exe_path, '/') != null) {
- return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
- }
-
- const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
- // PATH.len because it is >= the largest search_path
- // +1 for the / to join the search path and exe_path
- // +1 for the null terminating byte
- const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
- defer allocator.free(path_buf);
- var it = mem.tokenize(PATH, ":");
- var seen_eacces = false;
- var err: usize = undefined;
- while (it.next()) |search_path| {
- mem.copy(u8, path_buf, search_path);
- path_buf[search_path.len] = '/';
- mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
- path_buf[search_path.len + exe_path.len + 1] = 0;
- err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
- assert(err > 0);
- if (err == posix.EACCES) {
- seen_eacces = true;
- } else if (err != posix.ENOENT) {
- return posixExecveErrnoToErr(err);
- }
- }
- if (seen_eacces) {
- err = posix.EACCES;
- }
- return posixExecveErrnoToErr(err);
-}
-
-pub const PosixExecveError = error{
- SystemResources,
- AccessDenied,
- InvalidExe,
- FileSystem,
- IsDir,
- FileNotFound,
- NotDir,
- FileBusy,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-fn posixExecveErrnoToErr(err: usize) PosixExecveError {
- assert(err > 0);
- switch (err) {
- posix.EFAULT => unreachable,
- posix.E2BIG => return error.SystemResources,
- posix.EMFILE => return error.SystemResources,
- posix.ENAMETOOLONG => return error.SystemResources,
- posix.ENFILE => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EINVAL => return error.InvalidExe,
- posix.ENOEXEC => return error.InvalidExe,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.FileSystem,
- posix.EISDIR => return error.IsDir,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ETXTBSY => return error.FileBusy,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
-pub var posix_environ_raw: [][*]u8 = undefined;
-
-/// See std.elf for the constants.
-pub fn linuxGetAuxVal(index: usize) usize {
- if (builtin.link_libc) {
- return usize(std.c.getauxval(index));
- } else if (linux_elf_aux_maybe) |auxv| {
- var i: usize = 0;
- while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
- if (auxv[i].a_type == index)
- return auxv[i].a_un.a_val;
- }
- }
- return 0;
-}
-
-pub fn getBaseAddress() usize {
- switch (builtin.os) {
- builtin.Os.linux => {
- const base = linuxGetAuxVal(std.elf.AT_BASE);
- if (base != 0) {
- return base;
- }
- const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
- return phdr - @sizeOf(std.elf.Ehdr);
- },
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- return @ptrToInt(&std.c._mh_execute_header);
- },
- builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// Caller must free result when done.
-/// TODO make this go through libc when we have it
-pub fn getEnvMap(allocator: *Allocator) !BufMap {
- var result = BufMap.init(allocator);
- errdefer result.deinit();
-
- if (is_windows) {
- const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
- defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
-
- var i: usize = 0;
- while (true) {
- if (ptr[i] == 0) return result;
-
- const key_start = i;
-
- while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
- const key_w = ptr[key_start..i];
- const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
- errdefer allocator.free(key);
-
- if (ptr[i] == '=') i += 1;
-
- const value_start = i;
- while (ptr[i] != 0) : (i += 1) {}
- const value_w = ptr[value_start..i];
- const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
- errdefer allocator.free(value);
-
- i += 1; // skip over null byte
-
- try result.setMove(key, value);
- }
- } else {
- for (posix_environ_raw) |ptr| {
- var line_i: usize = 0;
- while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
- const key = ptr[0..line_i];
-
- var end_i: usize = line_i;
- while (ptr[end_i] != 0) : (end_i += 1) {}
- const value = ptr[line_i + 1 .. end_i];
-
- try result.set(key, value);
- }
- return result;
- }
-}
-
-test "os.getEnvMap" {
- var env = try getEnvMap(std.debug.global_allocator);
- defer env.deinit();
-}
-
-/// TODO make this go through libc when we have it
-pub fn getEnvPosix(key: []const u8) ?[]const u8 {
- for (posix_environ_raw) |ptr| {
- var line_i: usize = 0;
- while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
- const this_key = ptr[0..line_i];
- if (!mem.eql(u8, key, this_key)) continue;
-
- var end_i: usize = line_i;
- while (ptr[end_i] != 0) : (end_i += 1) {}
- const this_value = ptr[line_i + 1 .. end_i];
-
- return this_value;
- }
- return null;
-}
-
-pub const GetEnvVarOwnedError = error{
- OutOfMemory,
- EnvironmentVariableNotFound,
-
- /// See https://github.com/ziglang/zig/issues/1774
- InvalidUtf8,
-};
-
-/// Caller must free returned memory.
-/// TODO make this go through libc when we have it
-pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
- if (is_windows) {
- const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
- defer allocator.free(key_with_null);
-
- var buf = try allocator.alloc(u16, 256);
- defer allocator.free(buf);
-
- while (true) {
- const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
- const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
-
- if (result == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
- else => {
- _ = unexpectedErrorWindows(err);
- return error.EnvironmentVariableNotFound;
- },
- };
- }
-
- if (result > buf.len) {
- buf = try allocator.realloc(u16, buf, result);
- continue;
- }
-
- return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
- error.DanglingSurrogateHalf => return error.InvalidUtf8,
- error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
- error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
- error.OutOfMemory => return error.OutOfMemory,
- };
- }
- } else {
- const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
- return mem.dupe(allocator, u8, result);
- }
-}
-
-test "os.getEnvVarOwned" {
- var ga = debug.global_allocator;
- testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
-}
-
-/// Caller must free the returned memory.
-pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- return mem.dupe(allocator, u8, try getCwd(&buf));
-}
-
-pub const GetCwdError = error{Unexpected};
-
-/// The result is a slice of out_buffer.
-pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
- switch (builtin.os) {
- Os.windows => {
- var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
- const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
- const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
- if (result == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
- assert(result <= utf16le_buf.len);
- const utf16le_slice = utf16le_buf[0..result];
- // Trust that Windows gives us valid UTF-16LE.
- const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
- return out_buffer[0..end_index];
- },
- else => {
- const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
- switch (err) {
- 0 => return cstr.toSlice(out_buffer),
- posix.ERANGE => unreachable,
- else => return unexpectedErrorPosix(err),
- }
- },
- }
-}
-
-test "os.getCwd" {
- // at least call it so it gets compiled
- _ = getCwdAlloc(debug.global_allocator);
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- _ = getCwd(&buf);
-}
-
-pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
-
-/// TODO add a symLinkC variant
-pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
- if (is_windows) {
- return symLinkWindows(existing_path, new_path);
- } else {
- return symLinkPosix(existing_path, new_path);
- }
-}
-
-pub const WindowsSymLinkError = error{
- NameTooLong,
- InvalidUtf8,
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
- if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
- const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
- const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
- return symLinkW(&existing_path_w, &new_path_w);
-}
-
-pub const PosixSymLinkError = error{
- AccessDenied,
- DiskQuota,
- PathAlreadyExists,
- FileSystem,
- SymLinkLoop,
- NameTooLong,
- FileNotFound,
- SystemResources,
- NoSpaceLeft,
- ReadOnlyFileSystem,
- NotDir,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
- const err = posix.getErrno(posix.symlink(existing_path, new_path));
- switch (err) {
- 0 => return,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EDQUOT => return error.DiskQuota,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
- const existing_path_c = try toPosixPath(existing_path);
- const new_path_c = try toPosixPath(new_path);
- return symLinkPosixC(&existing_path_c, &new_path_c);
-}
-
-// here we replace the standard +/ with -_ so that it can be used in a file name
-const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
-
-/// TODO remove the allocator requirement from this API
-pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
- if (symLink(existing_path, new_path)) {
- return;
- } else |err| switch (err) {
- error.PathAlreadyExists => {},
- else => return err, // TODO zig should know this set does not include PathAlreadyExists
- }
-
- const dirname = os.path.dirname(new_path) orelse ".";
-
- var rand_buf: [12]u8 = undefined;
- const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
- defer allocator.free(tmp_path);
- mem.copy(u8, tmp_path[0..], dirname);
- tmp_path[dirname.len] = os.path.sep;
- while (true) {
- try getRandomBytes(rand_buf[0..]);
- b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
-
- if (symLink(existing_path, tmp_path)) {
- return rename(tmp_path, new_path);
- } else |err| switch (err) {
- error.PathAlreadyExists => continue,
- else => return err, // TODO zig should know this set does not include PathAlreadyExists
- }
- }
-}
-
-pub const DeleteFileError = error{
- FileNotFound,
- AccessDenied,
- FileBusy,
- FileSystem,
- IsDir,
- SymLinkLoop,
- NameTooLong,
- NotDir,
- SystemResources,
- ReadOnlyFileSystem,
-
- /// On Windows, file paths must be valid Unicode.
- InvalidUtf8,
-
- /// On Windows, file paths cannot contain these characters:
- /// '/', '*', '?', '"', '<', '>', '|'
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
- if (builtin.os == Os.windows) {
- const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
- return deleteFileW(&file_path_w);
- } else {
- const file_path_c = try toPosixPath(file_path);
- return deleteFileC(&file_path_c);
- }
-}
-
-pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
- if (windows.DeleteFileW(file_path) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
- windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
- windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
- if (is_windows) {
- const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
- return deleteFileW(&file_path_w);
- } else {
- const err = posix.getErrno(posix.unlink(file_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EIO => return error.FileSystem,
- posix.EISDIR => return error.IsDir,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
- }
-}
-
-/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
-/// merged and readily available,
-/// there is a possibility of power loss or application termination leaving temporary files present
-/// in the same directory as dest_path.
-/// Destination file will have the same mode as the source file.
-pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
- var in_file = try os.File.openRead(source_path);
- defer in_file.close();
-
- const mode = try in_file.mode();
-
- var atomic_file = try AtomicFile.init(dest_path, mode);
- defer atomic_file.deinit();
-
- var buf: [page_size]u8 = undefined;
- while (true) {
- const amt = try in_file.readFull(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
-}
-
-/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
-/// merged and readily available,
-/// there is a possibility of power loss or application termination leaving temporary files present
-pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
- var in_file = try os.File.openRead(source_path);
- defer in_file.close();
-
- var atomic_file = try AtomicFile.init(dest_path, mode);
- defer atomic_file.deinit();
-
- var buf: [page_size]u8 = undefined;
- while (true) {
- const amt = try in_file.read(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
-}
-
-pub const AtomicFile = struct {
- file: os.File,
- tmp_path_buf: [MAX_PATH_BYTES]u8,
- dest_path: []const u8,
- finished: bool,
-
- const InitError = os.File.OpenError;
-
- /// dest_path must remain valid for the lifetime of AtomicFile
- /// call finish to atomically replace dest_path with contents
- /// TODO once we have null terminated pointers, use the
- /// openWriteNoClobberN function
- pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
- const dirname = os.path.dirname(dest_path);
- var rand_buf: [12]u8 = undefined;
- const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
- const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
- const tmp_path_len = dirname_component_len + encoded_rand_len;
- var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
- if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
-
- if (dirname) |dir| {
- mem.copy(u8, tmp_path_buf[0..], dir);
- tmp_path_buf[dir.len] = os.path.sep;
- }
-
- tmp_path_buf[tmp_path_len] = 0;
-
- while (true) {
- try getRandomBytes(rand_buf[0..]);
- b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
-
- const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
- error.PathAlreadyExists => continue,
- // TODO zig should figure out that this error set does not include PathAlreadyExists since
- // it is handled in the above switch
- else => return err,
- };
-
- return AtomicFile{
- .file = file,
- .tmp_path_buf = tmp_path_buf,
- .dest_path = dest_path,
- .finished = false,
- };
- }
- }
-
- /// always call deinit, even after successful finish()
- pub fn deinit(self: *AtomicFile) void {
- if (!self.finished) {
- self.file.close();
- deleteFileC(&self.tmp_path_buf) catch {};
- self.finished = true;
- }
- }
-
- pub fn finish(self: *AtomicFile) !void {
- assert(!self.finished);
- self.file.close();
- self.finished = true;
- if (is_posix) {
- const dest_path_c = try toPosixPath(self.dest_path);
- return renameC(&self.tmp_path_buf, &dest_path_c);
- } else if (is_windows) {
- const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
- const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
- return renameW(&tmp_path_w, &dest_path_w);
- } else {
- @compileError("Unsupported OS");
- }
- }
-};
-
-pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
- if (is_windows) {
- const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
- const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
- return renameW(&old_path_w, &new_path_w);
- } else {
- const err = posix.getErrno(posix.rename(old_path, new_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EDQUOT => return error.DiskQuota,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EISDIR => return error.IsDir,
- posix.ELOOP => return error.SymLinkLoop,
- posix.EMLINK => return error.LinkQuotaExceeded,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.ENOTEMPTY => return error.PathAlreadyExists,
- posix.EROFS => return error.ReadOnlyFileSystem,
- posix.EXDEV => return error.RenameAcrossMountPoints,
- else => return unexpectedErrorPosix(err),
- }
- }
-}
-
-pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
- const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
- if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-pub fn rename(old_path: []const u8, new_path: []const u8) !void {
- if (is_windows) {
- const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
- const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
- return renameW(&old_path_w, &new_path_w);
- } else {
- const old_path_c = try toPosixPath(old_path);
- const new_path_c = try toPosixPath(new_path);
- return renameC(&old_path_c, &new_path_c);
- }
-}
-
-pub fn makeDir(dir_path: []const u8) !void {
- if (is_windows) {
- return makeDirWindows(dir_path);
- } else {
- return makeDirPosix(dir_path);
- }
-}
-
-pub fn makeDirWindows(dir_path: []const u8) !void {
- const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
-
- if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
- windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
- else => unexpectedErrorWindows(err),
- };
- }
-}
-
-pub fn makeDirPosixC(dir_path: [*]const u8) !void {
- const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EDQUOT => return error.DiskQuota,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.EFAULT => unreachable,
- posix.ELOOP => return error.SymLinkLoop,
- posix.EMLINK => return error.LinkQuotaExceeded,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.ENOTDIR => return error.NotDir,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn makeDirPosix(dir_path: []const u8) !void {
- const dir_path_c = try toPosixPath(dir_path);
- return makeDirPosixC(&dir_path_c);
-}
-
-/// Calls makeDir recursively to make an entire path. Returns success if the path
-/// already exists and is a directory.
-/// TODO determine if we can remove the allocator requirement from this function
-pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
- const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
- defer allocator.free(resolved_path);
-
- var end_index: usize = resolved_path.len;
- while (true) {
- makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
- error.PathAlreadyExists => {
- // TODO stat the file and return an error if it's not a directory
- // this is important because otherwise a dangling symlink
- // could cause an infinite loop
- if (end_index == resolved_path.len) return;
- },
- error.FileNotFound => {
- // march end_index backward until next path component
- while (true) {
- end_index -= 1;
- if (os.path.isSep(resolved_path[end_index])) break;
- }
- continue;
- },
- else => return err,
- };
- if (end_index == resolved_path.len) return;
- // march end_index forward until next path component
- while (true) {
- end_index += 1;
- if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
- }
- }
-}
-
-pub const DeleteDirError = error{
- AccessDenied,
- FileBusy,
- SymLinkLoop,
- NameTooLong,
- FileNotFound,
- SystemResources,
- NotDir,
- DirNotEmpty,
- ReadOnlyFileSystem,
- InvalidUtf8,
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
- switch (builtin.os) {
- Os.windows => {
- const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
- return deleteDirW(&dir_path_w);
- },
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const err = posix.getErrno(posix.rmdir(dir_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOTDIR => return error.NotDir,
- posix.EEXIST => return error.DirNotEmpty,
- posix.ENOTEMPTY => return error.DirNotEmpty,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
- },
- else => @compileError("unimplemented"),
- }
-}
-
-pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
- if (windows.RemoveDirectoryW(dir_path_w) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-/// Returns ::error.DirNotEmpty if the directory is not empty.
-/// To delete a directory recursively, see ::deleteTree
-pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
- switch (builtin.os) {
- Os.windows => {
- const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
- return deleteDirW(&dir_path_w);
- },
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const dir_path_c = try toPosixPath(dir_path);
- return deleteDirC(&dir_path_c);
- },
- else => @compileError("unimplemented"),
- }
-}
-
-/// Whether ::full_path describes a symlink, file, or directory, this function
-/// removes it. If it cannot be removed because it is a non-empty directory,
-/// this function recursively removes its entries and then tries again.
-const DeleteTreeError = error{
- OutOfMemory,
- AccessDenied,
- FileTooBig,
- IsDir,
- SymLinkLoop,
- ProcessFdQuotaExceeded,
- NameTooLong,
- SystemFdQuotaExceeded,
- NoDevice,
- SystemResources,
- NoSpaceLeft,
- PathAlreadyExists,
- ReadOnlyFileSystem,
- NotDir,
- FileNotFound,
- FileSystem,
- FileBusy,
- DirNotEmpty,
- DeviceBusy,
-
- /// On Windows, file paths must be valid Unicode.
- InvalidUtf8,
-
- /// On Windows, file paths cannot contain these characters:
- /// '/', '*', '?', '"', '<', '>', '|'
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-/// TODO determine if we can remove the allocator requirement
-pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
- start_over: while (true) {
- var got_access_denied = false;
- // First, try deleting the item as a file. This way we don't follow sym links.
- if (deleteFile(full_path)) {
- return;
- } else |err| switch (err) {
- error.FileNotFound => return,
- error.IsDir => {},
- error.AccessDenied => got_access_denied = true,
-
- error.InvalidUtf8,
- error.SymLinkLoop,
- error.NameTooLong,
- error.SystemResources,
- error.ReadOnlyFileSystem,
- error.NotDir,
- error.FileSystem,
- error.FileBusy,
- error.BadPathName,
- error.Unexpected,
- => return err,
- }
- {
- var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
- error.NotDir => {
- if (got_access_denied) {
- return error.AccessDenied;
- }
- continue :start_over;
- },
-
- error.OutOfMemory,
- error.AccessDenied,
- error.FileTooBig,
- error.IsDir,
- error.SymLinkLoop,
- error.ProcessFdQuotaExceeded,
- error.NameTooLong,
- error.SystemFdQuotaExceeded,
- error.NoDevice,
- error.FileNotFound,
- error.SystemResources,
- error.NoSpaceLeft,
- error.PathAlreadyExists,
- error.Unexpected,
- error.InvalidUtf8,
- error.BadPathName,
- error.DeviceBusy,
- => return err,
- };
- defer dir.close();
-
- var full_entry_buf = ArrayList(u8).init(allocator);
- defer full_entry_buf.deinit();
-
- while (try dir.next()) |entry| {
- try full_entry_buf.resize(full_path.len + entry.name.len + 1);
- const full_entry_path = full_entry_buf.toSlice();
- mem.copy(u8, full_entry_path, full_path);
- full_entry_path[full_path.len] = path.sep;
- mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
-
- try deleteTree(allocator, full_entry_path);
- }
- }
- return deleteDir(full_path);
- }
-}
-
-pub const Dir = struct {
- handle: Handle,
- allocator: *Allocator,
-
- pub const Handle = switch (builtin.os) {
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
- fd: i32,
- seek: i64,
- buf: []u8,
- index: usize,
- end_index: usize,
- },
- Os.linux => struct {
- fd: i32,
- buf: []u8,
- index: usize,
- end_index: usize,
- },
- Os.windows => struct {
- handle: windows.HANDLE,
- find_file_data: windows.WIN32_FIND_DATAW,
- first: bool,
- name_data: [256]u8,
- },
- else => @compileError("unimplemented"),
- };
-
- pub const Entry = struct {
- name: []const u8,
- kind: Kind,
-
- pub const Kind = enum {
- BlockDevice,
- CharacterDevice,
- Directory,
- NamedPipe,
- SymLink,
- File,
- UnixDomainSocket,
- Whiteout,
- Unknown,
- };
- };
-
- pub const OpenError = error{
- FileNotFound,
- NotDir,
- AccessDenied,
- FileTooBig,
- IsDir,
- SymLinkLoop,
- ProcessFdQuotaExceeded,
- NameTooLong,
- SystemFdQuotaExceeded,
- NoDevice,
- SystemResources,
- NoSpaceLeft,
- PathAlreadyExists,
- OutOfMemory,
- InvalidUtf8,
- BadPathName,
- DeviceBusy,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
- };
-
- /// TODO remove the allocator requirement from this API
- pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
- return Dir{
- .allocator = allocator,
- .handle = switch (builtin.os) {
- Os.windows => blk: {
- var find_file_data: windows.WIN32_FIND_DATAW = undefined;
- const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
- break :blk Handle{
- .handle = handle,
- .find_file_data = find_file_data, // TODO guaranteed copy elision
- .first = true,
- .name_data = undefined,
- };
- },
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
- .fd = try posixOpen(
- dir_path,
- posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
- 0,
- ),
- .seek = 0,
- .index = 0,
- .end_index = 0,
- .buf = []u8{},
- },
- Os.linux => Handle{
- .fd = try posixOpen(
- dir_path,
- posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
- 0,
- ),
- .index = 0,
- .end_index = 0,
- .buf = []u8{},
- },
- else => @compileError("unimplemented"),
- },
- };
- }
-
- pub fn close(self: *Dir) void {
- switch (builtin.os) {
- Os.windows => {
- _ = windows.FindClose(self.handle.handle);
- },
- Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
- self.allocator.free(self.handle.buf);
- os.close(self.handle.fd);
- },
- else => @compileError("unimplemented"),
- }
- }
-
- /// Memory such as file names referenced in this returned entry becomes invalid
- /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
- pub fn next(self: *Dir) !?Entry {
- switch (builtin.os) {
- Os.linux => return self.nextLinux(),
- Os.macosx, Os.ios => return self.nextDarwin(),
- Os.windows => return self.nextWindows(),
- Os.freebsd => return self.nextFreebsd(),
- Os.netbsd => return self.nextFreebsd(),
- else => @compileError("unimplemented"),
- }
- }
-
- fn nextDarwin(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + darwin_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
-
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (darwin_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- posix.DT_WHT => Entry.Kind.Whiteout,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-
- fn nextWindows(self: *Dir) !?Entry {
- while (true) {
- if (self.handle.first) {
- self.handle.first = false;
- } else {
- if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
- return null;
- }
- const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
- if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
- continue;
- // Trust that Windows gives us valid UTF-16LE
- const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
- const name_utf8 = self.handle.name_data[0..name_utf8_len];
- const kind = blk: {
- const attrs = self.handle.find_file_data.dwFileAttributes;
- if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
- if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
- if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
- break :blk Entry.Kind.Unknown;
- };
- return Entry{
- .name = name_utf8,
- .kind = kind,
- };
- }
- }
-
- fn nextLinux(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + linux_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
-
- // skip . and .. entries
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (linux_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-
- fn nextFreebsd(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + freebsd_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
-
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (freebsd_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- posix.DT_WHT => Entry.Kind.Whiteout,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-};
-
-pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
- const path_buf = try allocator.alloc(u8, dir_path.len + 1);
- defer allocator.free(path_buf);
-
- mem.copy(u8, path_buf, dir_path);
- path_buf[dir_path.len] = 0;
-
- const err = posix.getErrno(posix.chdir(path_buf.ptr));
- if (err > 0) {
- return switch (err) {
- posix.EACCES => error.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EIO => error.FileSystem,
- posix.ELOOP => error.SymLinkLoop,
- posix.ENAMETOOLONG => error.NameTooLong,
- posix.ENOENT => error.FileNotFound,
- posix.ENOMEM => error.SystemResources,
- posix.ENOTDIR => error.NotDir,
- else => unexpectedErrorPosix(err),
- };
- }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
- const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return out_buffer[0..rc],
- posix.EACCES => return error.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOTDIR => return error.NotDir,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
- const file_path_c = try toPosixPath(file_path);
- return readLinkC(out_buffer, &file_path_c);
-}
-
-pub fn posix_setuid(uid: u32) !void {
- const err = posix.getErrno(posix.setuid(uid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setreuid(ruid: u32, euid: u32) !void {
- const err = posix.getErrno(posix.setreuid(ruid, euid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setgid(gid: u32) !void {
- const err = posix.getErrno(posix.setgid(gid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setregid(rgid: u32, egid: u32) !void {
- const err = posix.getErrno(posix.setregid(rgid, egid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub const WindowsGetStdHandleErrs = error{
- NoStdHandles,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
- if (windows.GetStdHandle(handle_id)) |handle| {
- if (handle == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
- return handle;
- } else {
- return error.NoStdHandles;
- }
-}
-
-pub const ArgIteratorPosix = struct {
- index: usize,
- count: usize,
-
- pub fn init() ArgIteratorPosix {
- return ArgIteratorPosix{
- .index = 0,
- .count = raw.len,
- };
- }
-
- pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
- if (self.index == self.count) return null;
-
- const s = raw[self.index];
- self.index += 1;
- return cstr.toSlice(s);
- }
-
- pub fn skip(self: *ArgIteratorPosix) bool {
- if (self.index == self.count) return false;
-
- self.index += 1;
- return true;
- }
-
- /// This is marked as public but actually it's only meant to be used
- /// internally by zig's startup code.
- pub var raw: [][*]u8 = undefined;
-};
-
-pub const ArgIteratorWindows = struct {
- index: usize,
- cmd_line: [*]const u8,
- in_quote: bool,
- quote_count: usize,
- seen_quote_count: usize,
-
- pub const NextError = error{OutOfMemory};
-
- pub fn init() ArgIteratorWindows {
- return initWithCmdLine(windows.GetCommandLineA());
- }
-
- pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
- return ArgIteratorWindows{
- .index = 0,
- .cmd_line = cmd_line,
- .in_quote = false,
- .quote_count = countQuotes(cmd_line),
- .seen_quote_count = 0,
- };
- }
-
- /// You must free the returned memory when done.
- pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
- // march forward over whitespace
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return null,
- ' ', '\t' => continue,
- else => break,
- }
- }
-
- return self.internalNext(allocator);
- }
-
- pub fn skip(self: *ArgIteratorWindows) bool {
- // march forward over whitespace
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return false,
- ' ', '\t' => continue,
- else => break,
- }
- }
-
- var backslash_count: usize = 0;
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return true,
- '"' => {
- const quote_is_real = backslash_count % 2 == 0;
- if (quote_is_real) {
- self.seen_quote_count += 1;
- }
- },
- '\\' => {
- backslash_count += 1;
- },
- ' ', '\t' => {
- if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
- return true;
- }
- backslash_count = 0;
- },
- else => {
- backslash_count = 0;
- continue;
- },
- }
- }
- }
-
- fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
- var buf = try Buffer.initSize(allocator, 0);
- defer buf.deinit();
-
- var backslash_count: usize = 0;
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return buf.toOwnedSlice(),
- '"' => {
- const quote_is_real = backslash_count % 2 == 0;
- try self.emitBackslashes(&buf, backslash_count / 2);
- backslash_count = 0;
-
- if (quote_is_real) {
- self.seen_quote_count += 1;
- if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
- try buf.appendByte('"');
- }
- } else {
- try buf.appendByte('"');
- }
- },
- '\\' => {
- backslash_count += 1;
- },
- ' ', '\t' => {
- try self.emitBackslashes(&buf, backslash_count);
- backslash_count = 0;
- if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
- try buf.appendByte(byte);
- } else {
- return buf.toOwnedSlice();
- }
- },
- else => {
- try self.emitBackslashes(&buf, backslash_count);
- backslash_count = 0;
- try buf.appendByte(byte);
- },
- }
- }
- }
-
- fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
- var i: usize = 0;
- while (i < emit_count) : (i += 1) {
- try buf.appendByte('\\');
- }
- }
-
- fn countQuotes(cmd_line: [*]const u8) usize {
- var result: usize = 0;
- var backslash_count: usize = 0;
- var index: usize = 0;
- while (true) : (index += 1) {
- const byte = cmd_line[index];
- switch (byte) {
- 0 => return result,
- '\\' => backslash_count += 1,
- '"' => {
- result += 1 - (backslash_count % 2);
- backslash_count = 0;
- },
- else => {
- backslash_count = 0;
- },
- }
- }
- }
-};
-
-pub const ArgIterator = struct {
- const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
-
- inner: InnerType,
-
- pub fn init() ArgIterator {
- return ArgIterator{ .inner = InnerType.init() };
- }
-
- pub const NextError = ArgIteratorWindows.NextError;
-
- /// You must free the returned memory when done.
- pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
- if (builtin.os == Os.windows) {
- return self.inner.next(allocator);
- } else {
- return mem.dupe(allocator, u8, self.inner.next() orelse return null);
- }
- }
-
- /// If you only are targeting posix you can call this and not need an allocator.
- pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
- return self.inner.next();
- }
-
- /// Parse past 1 argument without capturing it.
- /// Returns `true` if skipped an arg, `false` if we are at the end.
- pub fn skip(self: *ArgIterator) bool {
- return self.inner.skip();
- }
-};
-
-pub fn args() ArgIterator {
- return ArgIterator.init();
-}
-
-/// Caller must call argsFree on result.
-pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
- // TODO refactor to only make 1 allocation.
- var it = args();
- var contents = try Buffer.initSize(allocator, 0);
- defer contents.deinit();
-
- var slice_list = ArrayList(usize).init(allocator);
- defer slice_list.deinit();
-
- while (it.next(allocator)) |arg_or_err| {
- const arg = try arg_or_err;
- defer allocator.free(arg);
- try contents.append(arg);
- try slice_list.append(arg.len);
- }
-
- const contents_slice = contents.toSliceConst();
- const slice_sizes = slice_list.toSliceConst();
- const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
- const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
- const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
- errdefer allocator.free(buf);
-
- const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
- const result_contents = buf[slice_list_bytes..];
- mem.copy(u8, result_contents, contents_slice);
-
- var contents_index: usize = 0;
- for (slice_sizes) |len, i| {
- const new_index = contents_index + len;
- result_slice_list[i] = result_contents[contents_index..new_index];
- contents_index = new_index;
- }
-
- return result_slice_list;
-}
-
-pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
- var total_bytes: usize = 0;
- for (args_alloc) |arg| {
- total_bytes += @sizeOf([]u8) + arg.len;
- }
- const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
- const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
- return allocator.free(aligned_allocated_buf);
-}
-
-test "windows arg parsing" {
- testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
- testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
- testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
- testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
- testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
- testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
-
- testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
- ".\\..\\zig-cache\\build",
- "bin\\zig.exe",
- ".\\..",
- ".\\..\\zig-cache",
- "--help",
- });
-}
-
-fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
- var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
- for (expected_args) |expected_arg| {
- const arg = it.next(debug.global_allocator).? catch unreachable;
- testing.expectEqualSlices(u8, expected_arg, arg);
- }
- testing.expect(it.next(debug.global_allocator) == null);
-}
-
-// TODO make this a build variable that you can set
-const unexpected_error_tracing = false;
-const UnexpectedError = error{
- /// The Operating System returned an undocumented error code.
- Unexpected,
-};
-
-/// Call this when you made a syscall or something that sets errno
-/// and you get an unexpected error.
-pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
- if (unexpected_error_tracing) {
- debug.warn("unexpected errno: {}\n", errno);
- debug.dumpCurrentStackTrace(null);
- }
- return error.Unexpected;
-}
-
-/// Call this when you made a windows DLL call or something that does SetLastError
-/// and you get an unexpected error.
-pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
- if (unexpected_error_tracing) {
- debug.warn("unexpected GetLastError(): {}\n", err);
- @breakpoint();
- debug.dumpCurrentStackTrace(null);
- }
- return error.Unexpected;
-}
-
-pub fn openSelfExe() !os.File {
- switch (builtin.os) {
- Os.linux => return os.File.openReadC(c"/proc/self/exe"),
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- const self_exe_path = try selfExePath(&buf);
- buf[self_exe_path.len] = 0;
- return os.File.openReadC(self_exe_path.ptr);
- },
- Os.windows => {
- var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const wide_slice = try selfExePathW(&buf);
- return os.File.openReadW(wide_slice.ptr);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-test "openSelfExe" {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
- else => return error.SkipZigTest, // Unsupported OS.
- }
-}
-
-pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
- const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
- const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
- assert(rc <= out_buffer.len);
- if (rc == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
- return out_buffer[0..rc];
-}
-
-/// Get the path to the current executable.
-/// If you only need the directory, use selfExeDirPath.
-/// If you only want an open file handle, use openSelfExe.
-/// This function may return an error if the current executable
-/// was deleted after spawning.
-/// Returned value is a slice of out_buffer.
-///
-/// On Linux, depends on procfs being mounted. If the currently executing binary has
-/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
-/// TODO make the return type of this a null terminated pointer
-pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
- switch (builtin.os) {
- Os.linux => return readLink(out_buffer, "/proc/self/exe"),
- Os.freebsd => {
- var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
- var out_len: usize = out_buffer.len;
- const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
-
- if (err == 0) return mem.toSlice(u8, out_buffer);
-
- return switch (err) {
- posix.EFAULT => error.BadAdress,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
- },
- Os.netbsd => {
- var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
- var out_len: usize = out_buffer.len;
- const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
-
- if (err == 0) return mem.toSlice(u8, out_buffer);
-
- return switch (err) {
- posix.EFAULT => error.BadAdress,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
- },
- Os.windows => {
- var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const utf16le_slice = try selfExePathW(&utf16le_buf);
- // Trust that Windows gives us valid UTF-16LE.
- const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
- return out_buffer[0..end_index];
- },
- Os.macosx, Os.ios => {
- var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
- const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
- if (rc != 0) return error.NameTooLong;
- return mem.toSlice(u8, out_buffer);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// `selfExeDirPath` except allocates the result on the heap.
-/// Caller owns returned memory.
-pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
-}
-
-/// Get the directory path that contains the current executable.
-/// Returned value is a slice of out_buffer.
-pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
- switch (builtin.os) {
- Os.linux => {
- // If the currently executing binary has been deleted,
- // the file path looks something like `/a/b/c/exe (deleted)`
- // This path cannot be opened, but it's valid for determining the directory
- // the executable was in when it was run.
- const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
- // Assume that /proc/self/exe has an absolute path, and therefore dirname
- // will not return null.
- return path.dirname(full_exe_path).?;
- },
- Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const self_exe_path = try selfExePath(out_buffer);
- // Assume that the OS APIs return absolute paths, and therefore dirname
- // will not return null.
- return path.dirname(self_exe_path).?;
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-pub fn isTty(handle: FileHandle) bool {
- if (is_windows) {
- return windows_util.windowsIsTty(handle);
- } else {
- if (builtin.link_libc) {
- return c.isatty(handle) != 0;
- } else {
- return posix.isatty(handle);
- }
- }
-}
-
-pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
- if (is_windows) {
- return windows_util.windowsIsCygwinPty(handle);
- } else {
- if (builtin.link_libc) {
- return c.isatty(handle) != 0;
- } else {
- return posix.isatty(handle);
- }
- }
-}
-
-pub const PosixSocketError = error{
- /// Permission to create a socket of the specified type and/or
- /// pro‐tocol is denied.
- PermissionDenied,
-
- /// The implementation does not support the specified address family.
- AddressFamilyNotSupported,
-
- /// Unknown protocol, or protocol family not available.
- ProtocolFamilyNotAvailable,
-
- /// The per-process limit on the number of open file descriptors has been reached.
- ProcessFdQuotaExceeded,
-
- /// The system-wide limit on the total number of open files has been reached.
- SystemFdQuotaExceeded,
-
- /// Insufficient memory is available. The socket cannot be created until sufficient
- /// resources are freed.
- SystemResources,
-
- /// The protocol type or the specified protocol is not supported within this domain.
- ProtocolNotSupported,
-};
-
-pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
- const rc = posix.socket(domain, socket_type, protocol);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EACCES => return PosixSocketError.PermissionDenied,
- posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
- posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
- posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
- posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
- posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub const PosixBindError = error{
- /// The address is protected, and the user is not the superuser.
- /// For UNIX domain sockets: Search permission is denied on a component
- /// of the path prefix.
- AccessDenied,
-
- /// The given address is already in use, or in the case of Internet domain sockets,
- /// The port number was specified as zero in the socket
- /// address structure, but, upon attempting to bind to an ephemeral port, it was
- /// determined that all port numbers in the ephemeral port range are currently in
- /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
- AddressInUse,
-
- /// A nonexistent interface was requested or the requested address was not local.
- AddressNotAvailable,
-
- /// Too many symbolic links were encountered in resolving addr.
- SymLinkLoop,
-
- /// addr is too long.
- NameTooLong,
-
- /// A component in the directory prefix of the socket pathname does not exist.
- FileNotFound,
-
- /// Insufficient kernel memory was available.
- SystemResources,
-
- /// A component of the path prefix is not a directory.
- NotDir,
-
- /// The socket inode would reside on a read-only filesystem.
- ReadOnlyFileSystem,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-/// addr is `&const T` where T is one of the sockaddr
-pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
- const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- posix.EACCES => return PosixBindError.AccessDenied,
- posix.EADDRINUSE => return PosixBindError.AddressInUse,
- posix.EBADF => unreachable, // always a race condition if this error is returned
- posix.EINVAL => unreachable,
- posix.ENOTSOCK => unreachable,
- posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
- posix.EFAULT => unreachable,
- posix.ELOOP => return PosixBindError.SymLinkLoop,
- posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
- posix.ENOENT => return PosixBindError.FileNotFound,
- posix.ENOMEM => return PosixBindError.SystemResources,
- posix.ENOTDIR => return PosixBindError.NotDir,
- posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-const PosixListenError = error{
- /// Another socket is already listening on the same port.
- /// For Internet domain sockets, the socket referred to by sockfd had not previously
- /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
- /// was determined that all port numbers in the ephemeral port range are currently in
- /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
- AddressInUse,
-
- /// The file descriptor sockfd does not refer to a socket.
- FileDescriptorNotASocket,
-
- /// The socket is not of a type that supports the listen() operation.
- OperationNotSupported,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
- const rc = posix.listen(sockfd, backlog);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- posix.EADDRINUSE => return PosixListenError.AddressInUse,
- posix.EBADF => unreachable,
- posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub const PosixAcceptError = error{
- ConnectionAborted,
-
- /// The per-process limit on the number of open file descriptors has been reached.
- ProcessFdQuotaExceeded,
-
- /// The system-wide limit on the total number of open files has been reached.
- SystemFdQuotaExceeded,
-
- /// Not enough free memory. This often means that the memory allocation is limited
- /// by the socket buffer limits, not by the system memory.
- SystemResources,
-
- /// The file descriptor sockfd does not refer to a socket.
- FileDescriptorNotASocket,
-
- /// The referenced socket is not of type SOCK_STREAM.
- OperationNotSupported,
-
- ProtocolFailure,
-
- /// Firewall rules forbid connection.
- BlockedByFirewall,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
- while (true) {
- var sockaddr_size = u32(@sizeOf(posix.sockaddr));
- const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EINTR => continue,
- else => return unexpectedErrorPosix(err),
-
- posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
- posix.ENOBUFS => return PosixAcceptError.SystemResources,
- posix.ENOMEM => return PosixAcceptError.SystemResources,
- posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
- posix.EPROTO => return PosixAcceptError.ProtocolFailure,
- posix.EPERM => return PosixAcceptError.BlockedByFirewall,
- }
- }
-}
-
-/// Returns -1 if would block.
-pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
- while (true) {
- var sockaddr_size = u32(@sizeOf(posix.sockaddr));
- const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EINTR => continue,
- else => return unexpectedErrorPosix(err),
-
- posix.EAGAIN => return -1,
- posix.EBADF => unreachable, // always a race condition
- posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
- posix.ENOBUFS => return PosixAcceptError.SystemResources,
- posix.ENOMEM => return PosixAcceptError.SystemResources,
- posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
- posix.EPROTO => return PosixAcceptError.ProtocolFailure,
- posix.EPERM => return PosixAcceptError.BlockedByFirewall,
- }
- }
-}
-
-pub const LinuxEpollCreateError = error{
- /// The per-user limit on the number of epoll instances imposed by
- /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
- /// details.
- /// Or, The per-process limit on the number of open file descriptors has been reached.
- ProcessFdQuotaExceeded,
-
- /// The system-wide limit on the total number of open files has been reached.
- SystemFdQuotaExceeded,
-
- /// There was insufficient memory to create the kernel object.
- SystemResources,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
- const rc = posix.epoll_create1(flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- else => return unexpectedErrorPosix(err),
-
- posix.EINVAL => unreachable,
- posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
- posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
- posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
- }
-}
-
-pub const LinuxEpollCtlError = error{
- /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
- /// with this epoll instance.
- FileDescriptorAlreadyPresentInSet,
-
- /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
- /// circular loop of epoll instances monitoring one another.
- OperationCausesCircularLoop,
-
- /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
- /// instance.
- FileDescriptorNotRegistered,
-
- /// There was insufficient memory to handle the requested op control operation.
- SystemResources,
-
- /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
- /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
- /// See epoll(7) for further details.
- UserResourceLimitReached,
-
- /// The target file fd does not support epoll. This error can occur if fd refers to,
- /// for example, a regular file or a directory.
- FileDescriptorIncompatibleWithEpoll,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
- const rc = posix.epoll_ctl(epfd, op, fd, event);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EBADF => unreachable, // always a race condition if this happens
- posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
- posix.EINVAL => unreachable,
- posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
- posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
- posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
- posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
- posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
- }
-}
-
-pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
- while (true) {
- const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EINTR => continue,
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- else => unreachable,
- }
- }
-}
-
-pub const LinuxEventFdError = error{
- InvalidFlagValue,
- SystemResources,
- ProcessFdQuotaExceeded,
- SystemFdQuotaExceeded,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
- const rc = posix.eventfd(initval, flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- else => return unexpectedErrorPosix(err),
-
- posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
- posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
- posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
- posix.ENODEV => return LinuxEventFdError.SystemResources,
- posix.ENOMEM => return LinuxEventFdError.SystemResources,
- }
-}
-
-pub const PosixGetSockNameError = error{
- /// Insufficient resources were available in the system to perform the operation.
- SystemResources,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
- var addr: posix.sockaddr = undefined;
- var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
- const rc = posix.getsockname(sockfd, &addr, &addrlen);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return addr,
- else => return unexpectedErrorPosix(err),
-
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENOTSOCK => unreachable,
- posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
- }
-}
-
-pub const PosixConnectError = error{
- /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
- /// file, or search permission is denied for one of the directories in the path prefix.
- /// or
- /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
- /// the connection request failed because of a local firewall rule.
- PermissionDenied,
-
- /// Local address is already in use.
- AddressInUse,
-
- /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
- /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
- /// in the ephemeral port range are currently in use. See the discussion of
- /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
- AddressNotAvailable,
-
- /// The passed address didn't have the correct address family in its sa_family field.
- AddressFamilyNotSupported,
-
- /// Insufficient entries in the routing cache.
- SystemResources,
-
- /// A connect() on a stream socket found no one listening on the remote address.
- ConnectionRefused,
-
- /// Network is unreachable.
- NetworkUnreachable,
-
- /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
- /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
- ConnectionTimedOut,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
- while (true) {
- const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
- posix.EINTR => continue,
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
- }
- }
-}
-
-/// Same as posixConnect except it is for blocking socket file descriptors.
-/// It expects to receive EINPROGRESS.
-pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
- while (true) {
- const rc = posix.connect(sockfd, sockaddr, len);
- const err = posix.getErrno(rc);
- switch (err) {
- 0, posix.EINPROGRESS => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EINTR => continue,
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
- }
- }
-}
-
-pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
- var err_code: i32 = undefined;
- var size: u32 = @sizeOf(i32);
- const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
- assert(size == 4);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => switch (err_code) {
- 0 => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
- },
- else => return unexpectedErrorPosix(err),
- posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
- posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
- posix.EINVAL => unreachable,
- posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- }
-}
-
-pub const Thread = struct {
- data: Data,
-
- pub const use_pthreads = is_posix and builtin.link_libc;
-
- /// Represents a kernel thread handle.
- /// May be an integer or a pointer depending on the platform.
- /// On Linux and POSIX, this is the same as Id.
- pub const Handle = if (use_pthreads)
- c.pthread_t
- else switch (builtin.os) {
- builtin.Os.linux => i32,
- builtin.Os.windows => windows.HANDLE,
- else => @compileError("Unsupported OS"),
- };
-
- /// Represents a unique ID per thread.
- /// May be an integer or pointer depending on the platform.
- /// On Linux and POSIX, this is the same as Handle.
- pub const Id = switch (builtin.os) {
- builtin.Os.windows => windows.DWORD,
- else => Handle,
- };
-
- pub const Data = if (use_pthreads)
- struct {
- handle: Thread.Handle,
- mmap_addr: usize,
- mmap_len: usize,
- }
- else switch (builtin.os) {
- builtin.Os.linux => struct {
- handle: Thread.Handle,
- mmap_addr: usize,
- mmap_len: usize,
- tls_end_addr: usize,
- },
- builtin.Os.windows => struct {
- handle: Thread.Handle,
- alloc_start: *c_void,
- heap_handle: windows.HANDLE,
- },
- else => @compileError("Unsupported OS"),
- };
-
- /// Returns the ID of the calling thread.
- /// Makes a syscall every time the function is called.
- /// On Linux and POSIX, this Id is the same as a Handle.
- pub fn getCurrentId() Id {
- if (use_pthreads) {
- return c.pthread_self();
- } else
- return switch (builtin.os) {
- builtin.Os.linux => linux.gettid(),
- builtin.Os.windows => windows.GetCurrentThreadId(),
- else => @compileError("Unsupported OS"),
- };
- }
-
- /// Returns the handle of this thread.
- /// On Linux and POSIX, this is the same as Id.
- pub fn handle(self: Thread) Handle {
- return self.data.handle;
- }
-
- pub fn wait(self: *const Thread) void {
- if (use_pthreads) {
- const err = c.pthread_join(self.data.handle, null);
- switch (err) {
- 0 => {},
- posix.EINVAL => unreachable,
- posix.ESRCH => unreachable,
- posix.EDEADLK => unreachable,
- else => unreachable,
- }
- assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
- } else switch (builtin.os) {
- builtin.Os.linux => {
- while (true) {
- const pid_value = @atomicLoad(i32, &self.data.handle, builtin.AtomicOrder.SeqCst);
- if (pid_value == 0) break;
- const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
- switch (linux.getErrno(rc)) {
- 0 => continue,
- posix.EINTR => continue,
- posix.EAGAIN => continue,
- else => unreachable,
- }
- }
- assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
- },
- builtin.Os.windows => {
- assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
- assert(windows.CloseHandle(self.data.handle) != 0);
- assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
- },
- else => @compileError("Unsupported OS"),
- }
- }
-};
-
-pub const SpawnThreadError = error{
- /// A system-imposed limit on the number of threads was encountered.
- /// There are a number of limits that may trigger this error:
- /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
- /// which limits the number of processes and threads for a real
- /// user ID, was reached;
- /// * the kernel's system-wide limit on the number of processes and
- /// threads, /proc/sys/kernel/threads-max, was reached (see
- /// proc(5));
- /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
- /// reached (see proc(5)); or
- /// * the PID limit (pids.max) imposed by the cgroup "process num‐
- /// ber" (PIDs) controller was reached.
- ThreadQuotaExceeded,
-
- /// The kernel cannot allocate sufficient memory to allocate a task structure
- /// for the child, or to copy those parts of the caller's context that need to
- /// be copied.
- SystemResources,
-
- /// Not enough userland memory to spawn the thread.
- OutOfMemory,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub var linux_tls_phdr: ?*std.elf.Phdr = null;
-pub var linux_tls_img_src: [*]const u8 = undefined; // defined if linux_tls_phdr is
-
-/// caller must call wait on the returned thread
-/// fn startFn(@typeOf(context)) T
-/// where T is u8, noreturn, void, or !void
-/// caller must call wait on the returned thread
-pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
- if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
- // TODO compile-time call graph analysis to determine stack upper bound
- // https://github.com/ziglang/zig/issues/157
- const default_stack_size = 8 * 1024 * 1024;
-
- const Context = @typeOf(context);
- comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
-
- if (builtin.os == builtin.Os.windows) {
- const WinThread = struct {
- const OuterContext = struct {
- thread: Thread,
- inner: Context,
- };
- extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
- const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
- switch (@typeId(@typeOf(startFn).ReturnType)) {
- builtin.TypeId.Int => {
- return startFn(arg);
- },
- builtin.TypeId.Void => {
- startFn(arg);
- return 0;
- },
- else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
- }
- }
- };
-
- const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
- const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
- const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
- errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
- const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
- const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
- outer_context.* = WinThread.OuterContext{
- .thread = Thread{
- .data = Thread.Data{
- .heap_handle = heap_handle,
- .alloc_start = bytes_ptr,
- .handle = undefined,
- },
- },
- .inner = context,
- };
-
- const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
- outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- };
- return &outer_context.thread;
- }
-
- const MainFuncs = struct {
- extern fn linuxThreadMain(ctx_addr: usize) u8 {
- const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
-
- switch (@typeId(@typeOf(startFn).ReturnType)) {
- builtin.TypeId.Int => {
- return startFn(arg);
- },
- builtin.TypeId.Void => {
- startFn(arg);
- return 0;
- },
- else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
- }
- }
- extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
- if (@sizeOf(Context) == 0) {
- _ = startFn({});
- return null;
- } else {
- _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
- return null;
- }
- }
- };
-
- const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
-
- var stack_end_offset: usize = undefined;
- var thread_start_offset: usize = undefined;
- var context_start_offset: usize = undefined;
- var tls_start_offset: usize = undefined;
- const mmap_len = blk: {
- // First in memory will be the stack, which grows downwards.
- var l: usize = mem.alignForward(default_stack_size, os.page_size);
- stack_end_offset = l;
- // Above the stack, so that it can be in the same mmap call, put the Thread object.
- l = mem.alignForward(l, @alignOf(Thread));
- thread_start_offset = l;
- l += @sizeOf(Thread);
- // Next, the Context object.
- if (@sizeOf(Context) != 0) {
- l = mem.alignForward(l, @alignOf(Context));
- context_start_offset = l;
- l += @sizeOf(Context);
- }
- // Finally, the Thread Local Storage, if any.
- if (!Thread.use_pthreads) {
- if (linux_tls_phdr) |tls_phdr| {
- l = mem.alignForward(l, tls_phdr.p_align);
- tls_start_offset = l;
- l += tls_phdr.p_memsz;
- }
- }
- break :blk l;
- };
- const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
- if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
- errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
-
- const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
- thread_ptr.data.mmap_addr = mmap_addr;
- thread_ptr.data.mmap_len = mmap_len;
-
- var arg: usize = undefined;
- if (@sizeOf(Context) != 0) {
- arg = mmap_addr + context_start_offset;
- const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
- context_ptr.* = context;
- }
-
- if (Thread.use_pthreads) {
- // use pthreads
- var attr: c.pthread_attr_t = undefined;
- if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
- defer assert(c.pthread_attr_destroy(&attr) == 0);
-
- assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
-
- const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
- switch (err) {
- 0 => return thread_ptr,
- posix.EAGAIN => return SpawnThreadError.SystemResources,
- posix.EPERM => unreachable,
- posix.EINVAL => unreachable,
- else => return unexpectedErrorPosix(@intCast(usize, err)),
- }
- } else if (builtin.os == builtin.Os.linux) {
- var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
- posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
- posix.CLONE_DETACHED;
- var newtls: usize = undefined;
- if (linux_tls_phdr) |tls_phdr| {
- @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), linux_tls_img_src, tls_phdr.p_filesz);
- thread_ptr.data.tls_end_addr = mmap_addr + mmap_len;
- newtls = @ptrToInt(&thread_ptr.data.tls_end_addr);
- flags |= posix.CLONE_SETTLS;
- }
- const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return thread_ptr,
- posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
- posix.EINVAL => unreachable,
- posix.ENOMEM => return SpawnThreadError.SystemResources,
- posix.ENOSPC => unreachable,
- posix.EPERM => unreachable,
- posix.EUSERS => unreachable,
- else => return unexpectedErrorPosix(err),
- }
- } else {
- @compileError("Unsupported OS");
- }
-}
-
-pub fn posixWait(pid: i32) i32 {
- var status: i32 = undefined;
- while (true) {
- const err = posix.getErrno(posix.waitpid(pid, &status, 0));
- switch (err) {
- 0 => return status,
- posix.EINTR => continue,
- posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
- posix.EINVAL => unreachable, // The options argument was invalid
- else => unreachable,
- }
- }
-}
-
-pub fn posixFStat(fd: i32) !posix.Stat {
- var stat: posix.Stat = undefined;
- const err = posix.getErrno(posix.fstat(fd, &stat));
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.ENOMEM => error.SystemResources,
- else => os.unexpectedErrorPosix(err),
- };
- }
-
- return stat;
-}
-
-pub const CpuCountError = error{
- OutOfMemory,
- PermissionDenied,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
- switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- var count: c_int = undefined;
- var count_len: usize = @sizeOf(c_int);
- const rc = posix.sysctlbyname(switch (builtin.os) {
- builtin.Os.macosx => c"hw.logicalcpu",
- else => c"hw.ncpu",
- }, @ptrCast(*c_void, &count), &count_len, null, 0);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(usize, count),
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENOMEM => return CpuCountError.OutOfMemory,
- posix.ENOTDIR => unreachable,
- posix.EISDIR => unreachable,
- posix.ENOENT => unreachable,
- posix.EPERM => unreachable,
- else => return os.unexpectedErrorPosix(err),
- }
- },
- builtin.Os.linux => {
- const usize_count = 16;
- const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
-
- var set = try allocator.alloc(usize, usize_count);
- defer allocator.free(set);
-
- while (true) {
- const rc = posix.sched_getaffinity(0, set);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => {
- if (rc < set.len * @sizeOf(usize)) {
- const result = set[0 .. rc / @sizeOf(usize)];
- var sum: usize = 0;
- for (result) |x| {
- sum += @popCount(x);
- }
- return sum;
- } else {
- set = try allocator.realloc(usize, set, set.len * 2);
- continue;
- }
- },
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EPERM => return CpuCountError.PermissionDenied,
- posix.ESRCH => unreachable,
- else => return os.unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.windows => {
- var system_info: windows.SYSTEM_INFO = undefined;
- windows.GetSystemInfo(&system_info);
- return @intCast(usize, system_info.dwNumberOfProcessors);
- },
- else => @compileError("unsupported OS"),
- }
-}
-
-pub const BsdKQueueError = error{
- /// The per-process limit on the number of open file descriptors has been reached.
- ProcessFdQuotaExceeded,
-
- /// The system-wide limit on the total number of open files has been reached.
- SystemFdQuotaExceeded,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn bsdKQueue() BsdKQueueError!i32 {
- const rc = posix.kqueue();
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
- posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub const BsdKEventError = error{
- /// The process does not have permission to register a filter.
- AccessDenied,
-
- /// The event could not be found to be modified or deleted.
- EventNotFound,
-
- /// No memory was available to register the event.
- SystemResources,
-
- /// The specified process to attach to does not exist.
- ProcessNotFound,
-};
-
-pub fn bsdKEvent(
- kq: i32,
- changelist: []const posix.Kevent,
- eventlist: []posix.Kevent,
- timeout: ?*const posix.timespec,
-) BsdKEventError!usize {
- while (true) {
- const rc = posix.kevent(kq, changelist, eventlist, timeout);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EACCES => return BsdKEventError.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EBADF => unreachable,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.ENOENT => return BsdKEventError.EventNotFound,
- posix.ENOMEM => return BsdKEventError.SystemResources,
- posix.ESRCH => return BsdKEventError.ProcessNotFound,
- else => unreachable,
- }
- }
-}
-
-pub fn linuxINotifyInit1(flags: u32) !i32 {
- const rc = linux.inotify_init1(flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EINVAL => unreachable,
- posix.EMFILE => return error.ProcessFdQuotaExceeded,
- posix.ENFILE => return error.SystemFdQuotaExceeded,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
- const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EACCES => return error.AccessDenied,
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.UserResourceLimitReached,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
- const rc = linux.inotify_rm_watch(inotify_fd, wd);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EBADF => unreachable,
- posix.EINVAL => unreachable,
- else => unreachable,
- }
-}
diff --git a/std/os/linux.zig b/std/os/linux.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e7f822185bc495302a67eae30bf48048c1a81fdc
--- /dev/null
+++ b/std/os/linux.zig
@@ -0,0 +1,1541 @@
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const builtin = @import("builtin");
+const maxInt = std.math.maxInt;
+const vdso = @import("linux/vdso.zig");
+pub use switch (builtin.arch) {
+ builtin.Arch.x86_64 => @import("linux/x86_64.zig"),
+ builtin.Arch.i386 => @import("linux/i386.zig"),
+ builtin.Arch.aarch64 => @import("linux/arm64.zig"),
+ else => @compileError("unsupported arch"),
+};
+pub use @import("linux/errno.zig");
+
+pub const PATH_MAX = 4096;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const FUTEX_WAIT = 0;
+pub const FUTEX_WAKE = 1;
+pub const FUTEX_FD = 2;
+pub const FUTEX_REQUEUE = 3;
+pub const FUTEX_CMP_REQUEUE = 4;
+pub const FUTEX_WAKE_OP = 5;
+pub const FUTEX_LOCK_PI = 6;
+pub const FUTEX_UNLOCK_PI = 7;
+pub const FUTEX_TRYLOCK_PI = 8;
+pub const FUTEX_WAIT_BITSET = 9;
+
+pub const FUTEX_PRIVATE_FLAG = 128;
+
+pub const FUTEX_CLOCK_REALTIME = 256;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+pub const PROT_GROWSDOWN = 0x01000000;
+pub const PROT_GROWSUP = 0x02000000;
+
+pub const MAP_FAILED = maxInt(usize);
+pub const MAP_SHARED = 0x01;
+pub const MAP_PRIVATE = 0x02;
+pub const MAP_TYPE = 0x0f;
+pub const MAP_FIXED = 0x10;
+pub const MAP_ANONYMOUS = 0x20;
+pub const MAP_NORESERVE = 0x4000;
+pub const MAP_GROWSDOWN = 0x0100;
+pub const MAP_DENYWRITE = 0x0800;
+pub const MAP_EXECUTABLE = 0x1000;
+pub const MAP_LOCKED = 0x2000;
+pub const MAP_POPULATE = 0x8000;
+pub const MAP_NONBLOCK = 0x10000;
+pub const MAP_STACK = 0x20000;
+pub const MAP_HUGETLB = 0x40000;
+pub const MAP_FILE = 0;
+
+pub const F_OK = 0;
+pub const X_OK = 1;
+pub const W_OK = 2;
+pub const R_OK = 4;
+
+pub const WNOHANG = 1;
+pub const WUNTRACED = 2;
+pub const WSTOPPED = 2;
+pub const WEXITED = 4;
+pub const WCONTINUED = 8;
+pub const WNOWAIT = 0x1000000;
+
+pub const SA_NOCLDSTOP = 1;
+pub const SA_NOCLDWAIT = 2;
+pub const SA_SIGINFO = 4;
+pub const SA_ONSTACK = 0x08000000;
+pub const SA_RESTART = 0x10000000;
+pub const SA_NODEFER = 0x40000000;
+pub const SA_RESETHAND = 0x80000000;
+pub const SA_RESTORER = 0x04000000;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGBUS = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGUSR1 = 10;
+pub const SIGSEGV = 11;
+pub const SIGUSR2 = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGSTKFLT = 16;
+pub const SIGCHLD = 17;
+pub const SIGCONT = 18;
+pub const SIGSTOP = 19;
+pub const SIGTSTP = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGURG = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGIO = 29;
+pub const SIGPOLL = 29;
+pub const SIGPWR = 30;
+pub const SIGSYS = 31;
+pub const SIGUNUSED = SIGSYS;
+
+pub const O_RDONLY = 0o0;
+pub const O_WRONLY = 0o1;
+pub const O_RDWR = 0o2;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 0;
+pub const SIG_UNBLOCK = 1;
+pub const SIG_SETMASK = 2;
+
+pub const PROTO_ip = 0o000;
+pub const PROTO_icmp = 0o001;
+pub const PROTO_igmp = 0o002;
+pub const PROTO_ggp = 0o003;
+pub const PROTO_ipencap = 0o004;
+pub const PROTO_st = 0o005;
+pub const PROTO_tcp = 0o006;
+pub const PROTO_egp = 0o010;
+pub const PROTO_pup = 0o014;
+pub const PROTO_udp = 0o021;
+pub const PROTO_hmp = 0o024;
+pub const PROTO_xns_idp = 0o026;
+pub const PROTO_rdp = 0o033;
+pub const PROTO_iso_tp4 = 0o035;
+pub const PROTO_xtp = 0o044;
+pub const PROTO_ddp = 0o045;
+pub const PROTO_idpr_cmtp = 0o046;
+pub const PROTO_ipv6 = 0o051;
+pub const PROTO_ipv6_route = 0o053;
+pub const PROTO_ipv6_frag = 0o054;
+pub const PROTO_idrp = 0o055;
+pub const PROTO_rsvp = 0o056;
+pub const PROTO_gre = 0o057;
+pub const PROTO_esp = 0o062;
+pub const PROTO_ah = 0o063;
+pub const PROTO_skip = 0o071;
+pub const PROTO_ipv6_icmp = 0o072;
+pub const PROTO_ipv6_nonxt = 0o073;
+pub const PROTO_ipv6_opts = 0o074;
+pub const PROTO_rspf = 0o111;
+pub const PROTO_vmtp = 0o121;
+pub const PROTO_ospf = 0o131;
+pub const PROTO_ipip = 0o136;
+pub const PROTO_encap = 0o142;
+pub const PROTO_pim = 0o147;
+pub const PROTO_raw = 0o377;
+
+pub const SHUT_RD = 0;
+pub const SHUT_WR = 1;
+pub const SHUT_RDWR = 2;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+pub const SOCK_DCCP = 6;
+pub const SOCK_PACKET = 10;
+pub const SOCK_CLOEXEC = 0o2000000;
+pub const SOCK_NONBLOCK = 0o4000;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_AX25 = 3;
+pub const PF_IPX = 4;
+pub const PF_APPLETALK = 5;
+pub const PF_NETROM = 6;
+pub const PF_BRIDGE = 7;
+pub const PF_ATMPVC = 8;
+pub const PF_X25 = 9;
+pub const PF_INET6 = 10;
+pub const PF_ROSE = 11;
+pub const PF_DECnet = 12;
+pub const PF_NETBEUI = 13;
+pub const PF_SECURITY = 14;
+pub const PF_KEY = 15;
+pub const PF_NETLINK = 16;
+pub const PF_ROUTE = PF_NETLINK;
+pub const PF_PACKET = 17;
+pub const PF_ASH = 18;
+pub const PF_ECONET = 19;
+pub const PF_ATMSVC = 20;
+pub const PF_RDS = 21;
+pub const PF_SNA = 22;
+pub const PF_IRDA = 23;
+pub const PF_PPPOX = 24;
+pub const PF_WANPIPE = 25;
+pub const PF_LLC = 26;
+pub const PF_IB = 27;
+pub const PF_MPLS = 28;
+pub const PF_CAN = 29;
+pub const PF_TIPC = 30;
+pub const PF_BLUETOOTH = 31;
+pub const PF_IUCV = 32;
+pub const PF_RXRPC = 33;
+pub const PF_ISDN = 34;
+pub const PF_PHONET = 35;
+pub const PF_IEEE802154 = 36;
+pub const PF_CAIF = 37;
+pub const PF_ALG = 38;
+pub const PF_NFC = 39;
+pub const PF_VSOCK = 40;
+pub const PF_KCM = 41;
+pub const PF_QIPCRTR = 42;
+pub const PF_SMC = 43;
+pub const PF_MAX = 44;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_AX25 = PF_AX25;
+pub const AF_IPX = PF_IPX;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_NETROM = PF_NETROM;
+pub const AF_BRIDGE = PF_BRIDGE;
+pub const AF_ATMPVC = PF_ATMPVC;
+pub const AF_X25 = PF_X25;
+pub const AF_INET6 = PF_INET6;
+pub const AF_ROSE = PF_ROSE;
+pub const AF_DECnet = PF_DECnet;
+pub const AF_NETBEUI = PF_NETBEUI;
+pub const AF_SECURITY = PF_SECURITY;
+pub const AF_KEY = PF_KEY;
+pub const AF_NETLINK = PF_NETLINK;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_PACKET = PF_PACKET;
+pub const AF_ASH = PF_ASH;
+pub const AF_ECONET = PF_ECONET;
+pub const AF_ATMSVC = PF_ATMSVC;
+pub const AF_RDS = PF_RDS;
+pub const AF_SNA = PF_SNA;
+pub const AF_IRDA = PF_IRDA;
+pub const AF_PPPOX = PF_PPPOX;
+pub const AF_WANPIPE = PF_WANPIPE;
+pub const AF_LLC = PF_LLC;
+pub const AF_IB = PF_IB;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_TIPC = PF_TIPC;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_IUCV = PF_IUCV;
+pub const AF_RXRPC = PF_RXRPC;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_PHONET = PF_PHONET;
+pub const AF_IEEE802154 = PF_IEEE802154;
+pub const AF_CAIF = PF_CAIF;
+pub const AF_ALG = PF_ALG;
+pub const AF_NFC = PF_NFC;
+pub const AF_VSOCK = PF_VSOCK;
+pub const AF_KCM = PF_KCM;
+pub const AF_QIPCRTR = PF_QIPCRTR;
+pub const AF_SMC = PF_SMC;
+pub const AF_MAX = PF_MAX;
+
+pub const SO_DEBUG = 1;
+pub const SO_REUSEADDR = 2;
+pub const SO_TYPE = 3;
+pub const SO_ERROR = 4;
+pub const SO_DONTROUTE = 5;
+pub const SO_BROADCAST = 6;
+pub const SO_SNDBUF = 7;
+pub const SO_RCVBUF = 8;
+pub const SO_KEEPALIVE = 9;
+pub const SO_OOBINLINE = 10;
+pub const SO_NO_CHECK = 11;
+pub const SO_PRIORITY = 12;
+pub const SO_LINGER = 13;
+pub const SO_BSDCOMPAT = 14;
+pub const SO_REUSEPORT = 15;
+pub const SO_PASSCRED = 16;
+pub const SO_PEERCRED = 17;
+pub const SO_RCVLOWAT = 18;
+pub const SO_SNDLOWAT = 19;
+pub const SO_RCVTIMEO = 20;
+pub const SO_SNDTIMEO = 21;
+pub const SO_ACCEPTCONN = 30;
+pub const SO_SNDBUFFORCE = 32;
+pub const SO_RCVBUFFORCE = 33;
+pub const SO_PROTOCOL = 38;
+pub const SO_DOMAIN = 39;
+
+pub const SO_SECURITY_AUTHENTICATION = 22;
+pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
+pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
+
+pub const SO_BINDTODEVICE = 25;
+
+pub const SO_ATTACH_FILTER = 26;
+pub const SO_DETACH_FILTER = 27;
+pub const SO_GET_FILTER = SO_ATTACH_FILTER;
+
+pub const SO_PEERNAME = 28;
+pub const SO_TIMESTAMP = 29;
+pub const SCM_TIMESTAMP = SO_TIMESTAMP;
+
+pub const SO_PEERSEC = 31;
+pub const SO_PASSSEC = 34;
+pub const SO_TIMESTAMPNS = 35;
+pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
+pub const SO_MARK = 36;
+pub const SO_TIMESTAMPING = 37;
+pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
+pub const SO_RXQ_OVFL = 40;
+pub const SO_WIFI_STATUS = 41;
+pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
+pub const SO_PEEK_OFF = 42;
+pub const SO_NOFCS = 43;
+pub const SO_LOCK_FILTER = 44;
+pub const SO_SELECT_ERR_QUEUE = 45;
+pub const SO_BUSY_POLL = 46;
+pub const SO_MAX_PACING_RATE = 47;
+pub const SO_BPF_EXTENSIONS = 48;
+pub const SO_INCOMING_CPU = 49;
+pub const SO_ATTACH_BPF = 50;
+pub const SO_DETACH_BPF = SO_DETACH_FILTER;
+pub const SO_ATTACH_REUSEPORT_CBPF = 51;
+pub const SO_ATTACH_REUSEPORT_EBPF = 52;
+pub const SO_CNX_ADVICE = 53;
+pub const SCM_TIMESTAMPING_OPT_STATS = 54;
+pub const SO_MEMINFO = 55;
+pub const SO_INCOMING_NAPI_ID = 56;
+pub const SO_COOKIE = 57;
+pub const SCM_TIMESTAMPING_PKTINFO = 58;
+pub const SO_PEERGROUPS = 59;
+pub const SO_ZEROCOPY = 60;
+
+pub const SOL_SOCKET = 1;
+
+pub const SOL_IP = 0;
+pub const SOL_IPV6 = 41;
+pub const SOL_ICMPV6 = 58;
+
+pub const SOL_RAW = 255;
+pub const SOL_DECNET = 261;
+pub const SOL_X25 = 262;
+pub const SOL_PACKET = 263;
+pub const SOL_ATM = 264;
+pub const SOL_AAL = 265;
+pub const SOL_IRDA = 266;
+pub const SOL_NETBEUI = 267;
+pub const SOL_LLC = 268;
+pub const SOL_DCCP = 269;
+pub const SOL_NETLINK = 270;
+pub const SOL_TIPC = 271;
+pub const SOL_RXRPC = 272;
+pub const SOL_PPPOL2TP = 273;
+pub const SOL_BLUETOOTH = 274;
+pub const SOL_PNPIPE = 275;
+pub const SOL_RDS = 276;
+pub const SOL_IUCV = 277;
+pub const SOL_CAIF = 278;
+pub const SOL_ALG = 279;
+pub const SOL_NFC = 280;
+pub const SOL_KCM = 281;
+pub const SOL_TLS = 282;
+
+pub const SOMAXCONN = 128;
+
+pub const MSG_OOB = 0x0001;
+pub const MSG_PEEK = 0x0002;
+pub const MSG_DONTROUTE = 0x0004;
+pub const MSG_CTRUNC = 0x0008;
+pub const MSG_PROXY = 0x0010;
+pub const MSG_TRUNC = 0x0020;
+pub const MSG_DONTWAIT = 0x0040;
+pub const MSG_EOR = 0x0080;
+pub const MSG_WAITALL = 0x0100;
+pub const MSG_FIN = 0x0200;
+pub const MSG_SYN = 0x0400;
+pub const MSG_CONFIRM = 0x0800;
+pub const MSG_RST = 0x1000;
+pub const MSG_ERRQUEUE = 0x2000;
+pub const MSG_NOSIGNAL = 0x4000;
+pub const MSG_MORE = 0x8000;
+pub const MSG_WAITFORONE = 0x10000;
+pub const MSG_BATCH = 0x40000;
+pub const MSG_ZEROCOPY = 0x4000000;
+pub const MSG_FASTOPEN = 0x20000000;
+pub const MSG_CMSG_CLOEXEC = 0x40000000;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+pub const TCGETS = 0x5401;
+pub const TCSETS = 0x5402;
+pub const TCSETSW = 0x5403;
+pub const TCSETSF = 0x5404;
+pub const TCGETA = 0x5405;
+pub const TCSETA = 0x5406;
+pub const TCSETAW = 0x5407;
+pub const TCSETAF = 0x5408;
+pub const TCSBRK = 0x5409;
+pub const TCXONC = 0x540A;
+pub const TCFLSH = 0x540B;
+pub const TIOCEXCL = 0x540C;
+pub const TIOCNXCL = 0x540D;
+pub const TIOCSCTTY = 0x540E;
+pub const TIOCGPGRP = 0x540F;
+pub const TIOCSPGRP = 0x5410;
+pub const TIOCOUTQ = 0x5411;
+pub const TIOCSTI = 0x5412;
+pub const TIOCGWINSZ = 0x5413;
+pub const TIOCSWINSZ = 0x5414;
+pub const TIOCMGET = 0x5415;
+pub const TIOCMBIS = 0x5416;
+pub const TIOCMBIC = 0x5417;
+pub const TIOCMSET = 0x5418;
+pub const TIOCGSOFTCAR = 0x5419;
+pub const TIOCSSOFTCAR = 0x541A;
+pub const FIONREAD = 0x541B;
+pub const TIOCINQ = FIONREAD;
+pub const TIOCLINUX = 0x541C;
+pub const TIOCCONS = 0x541D;
+pub const TIOCGSERIAL = 0x541E;
+pub const TIOCSSERIAL = 0x541F;
+pub const TIOCPKT = 0x5420;
+pub const FIONBIO = 0x5421;
+pub const TIOCNOTTY = 0x5422;
+pub const TIOCSETD = 0x5423;
+pub const TIOCGETD = 0x5424;
+pub const TCSBRKP = 0x5425;
+pub const TIOCSBRK = 0x5427;
+pub const TIOCCBRK = 0x5428;
+pub const TIOCGSID = 0x5429;
+pub const TIOCGRS485 = 0x542E;
+pub const TIOCSRS485 = 0x542F;
+pub const TIOCGPTN = 0x80045430;
+pub const TIOCSPTLCK = 0x40045431;
+pub const TIOCGDEV = 0x80045432;
+pub const TCGETX = 0x5432;
+pub const TCSETX = 0x5433;
+pub const TCSETXF = 0x5434;
+pub const TCSETXW = 0x5435;
+pub const TIOCSIG = 0x40045436;
+pub const TIOCVHANGUP = 0x5437;
+pub const TIOCGPKT = 0x80045438;
+pub const TIOCGPTLCK = 0x80045439;
+pub const TIOCGEXCL = 0x80045440;
+
+pub const EPOLL_CLOEXEC = O_CLOEXEC;
+
+pub const EPOLL_CTL_ADD = 1;
+pub const EPOLL_CTL_DEL = 2;
+pub const EPOLL_CTL_MOD = 3;
+
+pub const EPOLLIN = 0x001;
+pub const EPOLLPRI = 0x002;
+pub const EPOLLOUT = 0x004;
+pub const EPOLLRDNORM = 0x040;
+pub const EPOLLRDBAND = 0x080;
+pub const EPOLLWRNORM = 0x100;
+pub const EPOLLWRBAND = 0x200;
+pub const EPOLLMSG = 0x400;
+pub const EPOLLERR = 0x008;
+pub const EPOLLHUP = 0x010;
+pub const EPOLLRDHUP = 0x2000;
+pub const EPOLLEXCLUSIVE = (u32(1) << 28);
+pub const EPOLLWAKEUP = (u32(1) << 29);
+pub const EPOLLONESHOT = (u32(1) << 30);
+pub const EPOLLET = (u32(1) << 31);
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_MONOTONIC = 1;
+pub const CLOCK_PROCESS_CPUTIME_ID = 2;
+pub const CLOCK_THREAD_CPUTIME_ID = 3;
+pub const CLOCK_MONOTONIC_RAW = 4;
+pub const CLOCK_REALTIME_COARSE = 5;
+pub const CLOCK_MONOTONIC_COARSE = 6;
+pub const CLOCK_BOOTTIME = 7;
+pub const CLOCK_REALTIME_ALARM = 8;
+pub const CLOCK_BOOTTIME_ALARM = 9;
+pub const CLOCK_SGI_CYCLE = 10;
+pub const CLOCK_TAI = 11;
+
+pub const CSIGNAL = 0x000000ff;
+pub const CLONE_VM = 0x00000100;
+pub const CLONE_FS = 0x00000200;
+pub const CLONE_FILES = 0x00000400;
+pub const CLONE_SIGHAND = 0x00000800;
+pub const CLONE_PTRACE = 0x00002000;
+pub const CLONE_VFORK = 0x00004000;
+pub const CLONE_PARENT = 0x00008000;
+pub const CLONE_THREAD = 0x00010000;
+pub const CLONE_NEWNS = 0x00020000;
+pub const CLONE_SYSVSEM = 0x00040000;
+pub const CLONE_SETTLS = 0x00080000;
+pub const CLONE_PARENT_SETTID = 0x00100000;
+pub const CLONE_CHILD_CLEARTID = 0x00200000;
+pub const CLONE_DETACHED = 0x00400000;
+pub const CLONE_UNTRACED = 0x00800000;
+pub const CLONE_CHILD_SETTID = 0x01000000;
+pub const CLONE_NEWCGROUP = 0x02000000;
+pub const CLONE_NEWUTS = 0x04000000;
+pub const CLONE_NEWIPC = 0x08000000;
+pub const CLONE_NEWUSER = 0x10000000;
+pub const CLONE_NEWPID = 0x20000000;
+pub const CLONE_NEWNET = 0x40000000;
+pub const CLONE_IO = 0x80000000;
+
+pub const EFD_SEMAPHORE = 1;
+pub const EFD_CLOEXEC = O_CLOEXEC;
+pub const EFD_NONBLOCK = O_NONBLOCK;
+
+pub const MS_RDONLY = 1;
+pub const MS_NOSUID = 2;
+pub const MS_NODEV = 4;
+pub const MS_NOEXEC = 8;
+pub const MS_SYNCHRONOUS = 16;
+pub const MS_REMOUNT = 32;
+pub const MS_MANDLOCK = 64;
+pub const MS_DIRSYNC = 128;
+pub const MS_NOATIME = 1024;
+pub const MS_NODIRATIME = 2048;
+pub const MS_BIND = 4096;
+pub const MS_MOVE = 8192;
+pub const MS_REC = 16384;
+pub const MS_SILENT = 32768;
+pub const MS_POSIXACL = (1 << 16);
+pub const MS_UNBINDABLE = (1 << 17);
+pub const MS_PRIVATE = (1 << 18);
+pub const MS_SLAVE = (1 << 19);
+pub const MS_SHARED = (1 << 20);
+pub const MS_RELATIME = (1 << 21);
+pub const MS_KERNMOUNT = (1 << 22);
+pub const MS_I_VERSION = (1 << 23);
+pub const MS_STRICTATIME = (1 << 24);
+pub const MS_LAZYTIME = (1 << 25);
+pub const MS_NOREMOTELOCK = (1 << 27);
+pub const MS_NOSEC = (1 << 28);
+pub const MS_BORN = (1 << 29);
+pub const MS_ACTIVE = (1 << 30);
+pub const MS_NOUSER = (1 << 31);
+
+pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
+
+pub const MS_MGC_VAL = 0xc0ed0000;
+pub const MS_MGC_MSK = 0xffff0000;
+
+pub const MNT_FORCE = 1;
+pub const MNT_DETACH = 2;
+pub const MNT_EXPIRE = 4;
+pub const UMOUNT_NOFOLLOW = 8;
+
+pub const IN_CLOEXEC = O_CLOEXEC;
+pub const IN_NONBLOCK = O_NONBLOCK;
+
+pub const IN_ACCESS = 0x00000001;
+pub const IN_MODIFY = 0x00000002;
+pub const IN_ATTRIB = 0x00000004;
+pub const IN_CLOSE_WRITE = 0x00000008;
+pub const IN_CLOSE_NOWRITE = 0x00000010;
+pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
+pub const IN_OPEN = 0x00000020;
+pub const IN_MOVED_FROM = 0x00000040;
+pub const IN_MOVED_TO = 0x00000080;
+pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
+pub const IN_CREATE = 0x00000100;
+pub const IN_DELETE = 0x00000200;
+pub const IN_DELETE_SELF = 0x00000400;
+pub const IN_MOVE_SELF = 0x00000800;
+pub const IN_ALL_EVENTS = 0x00000fff;
+
+pub const IN_UNMOUNT = 0x00002000;
+pub const IN_Q_OVERFLOW = 0x00004000;
+pub const IN_IGNORED = 0x00008000;
+
+pub const IN_ONLYDIR = 0x01000000;
+pub const IN_DONT_FOLLOW = 0x02000000;
+pub const IN_EXCL_UNLINK = 0x04000000;
+pub const IN_MASK_ADD = 0x20000000;
+
+pub const IN_ISDIR = 0x40000000;
+pub const IN_ONESHOT = 0x80000000;
+
+pub const S_IFMT = 0o170000;
+
+pub const S_IFDIR = 0o040000;
+pub const S_IFCHR = 0o020000;
+pub const S_IFBLK = 0o060000;
+pub const S_IFREG = 0o100000;
+pub const S_IFIFO = 0o010000;
+pub const S_IFLNK = 0o120000;
+pub const S_IFSOCK = 0o140000;
+
+pub const S_ISUID = 0o4000;
+pub const S_ISGID = 0o2000;
+pub const S_ISVTX = 0o1000;
+pub const S_IRUSR = 0o400;
+pub const S_IWUSR = 0o200;
+pub const S_IXUSR = 0o100;
+pub const S_IRWXU = 0o700;
+pub const S_IRGRP = 0o040;
+pub const S_IWGRP = 0o020;
+pub const S_IXGRP = 0o010;
+pub const S_IRWXG = 0o070;
+pub const S_IROTH = 0o004;
+pub const S_IWOTH = 0o002;
+pub const S_IXOTH = 0o001;
+pub const S_IRWXO = 0o007;
+
+pub fn S_ISREG(m: u32) bool {
+ return m & S_IFMT == S_IFREG;
+}
+
+pub fn S_ISDIR(m: u32) bool {
+ return m & S_IFMT == S_IFDIR;
+}
+
+pub fn S_ISCHR(m: u32) bool {
+ return m & S_IFMT == S_IFCHR;
+}
+
+pub fn S_ISBLK(m: u32) bool {
+ return m & S_IFMT == S_IFBLK;
+}
+
+pub fn S_ISFIFO(m: u32) bool {
+ return m & S_IFMT == S_IFIFO;
+}
+
+pub fn S_ISLNK(m: u32) bool {
+ return m & S_IFMT == S_IFLNK;
+}
+
+pub fn S_ISSOCK(m: u32) bool {
+ return m & S_IFMT == S_IFSOCK;
+}
+
+pub const TFD_NONBLOCK = O_NONBLOCK;
+pub const TFD_CLOEXEC = O_CLOEXEC;
+
+pub const TFD_TIMER_ABSTIME = 1;
+pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
+
+fn unsigned(s: i32) u32 {
+ return @bitCast(u32, s);
+}
+fn signed(s: u32) i32 {
+ return @bitCast(i32, s);
+}
+pub fn WEXITSTATUS(s: i32) i32 {
+ return signed((unsigned(s) & 0xff00) >> 8);
+}
+pub fn WTERMSIG(s: i32) i32 {
+ return signed(unsigned(s) & 0x7f);
+}
+pub fn WSTOPSIG(s: i32) i32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: i32) bool {
+ return WTERMSIG(s) == 0;
+}
+pub fn WIFSTOPPED(s: i32) bool {
+ return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
+}
+pub fn WIFSIGNALED(s: i32) bool {
+ return (unsigned(s) & 0xffff) -% 1 < 0xff;
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+/// Get the errno from a syscall return value, or 0 for no error.
+pub fn getErrno(r: usize) usize {
+ const signed_r = @bitCast(isize, r);
+ return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+}
+
+pub fn dup2(old: i32, new: i32) usize {
+ return dup3(old, new, 0);
+}
+
+pub fn dup3(old: i32, new: i32, flags: u32) usize {
+ return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn chdir(path: [*]const u8) usize {
+ return syscall1(SYS_chdir, @ptrToInt(path));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn chroot(path: [*]const u8) usize {
+ return syscall1(SYS_chroot, @ptrToInt(path));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
+ return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
+}
+
+pub fn fork() usize {
+ return clone2(SIGCHLD, 0);
+}
+
+/// This must be inline, and inline call the syscall function, because if the
+/// child does a return it will clobber the parent's stack.
+/// It is advised to avoid this function and use clone instead, because
+/// the compiler is not aware of how vfork affects control flow and you may
+/// see different results in optimized builds.
+pub inline fn vfork() usize {
+ return @inlineCall(syscall0, SYS_vfork);
+}
+
+pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
+ return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
+}
+
+pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize {
+ return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val));
+}
+
+pub fn getcwd(buf: [*]u8, size: usize) usize {
+ return syscall2(SYS_getcwd, @ptrToInt(buf), size);
+}
+
+pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
+ return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
+}
+
+pub fn inotify_init1(flags: u32) usize {
+ return syscall1(SYS_inotify_init1, flags);
+}
+
+pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
+ return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
+}
+
+pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
+ return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
+}
+
+pub fn isatty(fd: i32) bool {
+ var wsz: winsize = undefined;
+ return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
+ return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
+ return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn mkdir(path: [*]const u8, mode: u32) usize {
+ return mkdirat(AT_FDCWD, path, mode);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
+ return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize {
+ return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn umount(special: [*]const u8) usize {
+ return syscall2(SYS_umount2, @ptrToInt(special), 0);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn umount2(special: [*]const u8, flags: u32) usize {
+ return syscall2(SYS_umount2, @ptrToInt(special), flags);
+}
+
+pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
+ return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
+}
+
+pub fn mprotect(address: usize, length: usize, protection: usize) usize {
+ return syscall3(SYS_mprotect, address, length, protection);
+}
+
+pub fn munmap(address: usize, length: usize) usize {
+ return syscall2(SYS_munmap, address, length);
+}
+
+pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
+ return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
+}
+
+pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
+ return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
+}
+
+pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
+ return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
+}
+
+pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
+ return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
+}
+
+pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
+ return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn rmdir(path: [*]const u8) usize {
+ return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
+ return symlinkat(existing, AT_FDCWD, new);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
+ return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
+ return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn access(path: [*]const u8, mode: u32) usize {
+ return faccessat(AT_FDCWD, path, mode);
+}
+
+pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
+ return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
+}
+
+pub fn pipe(fd: *[2]i32) usize {
+ return pipe2(fd, 0);
+}
+
+pub fn pipe2(fd: *[2]i32, flags: u32) usize {
+ return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
+}
+
+pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
+ return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
+}
+
+pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
+ return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn rename(old: [*]const u8, new: [*]const u8) usize {
+ return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
+ return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
+ return openat(AT_FDCWD, path, flags, perm);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn create(path: [*]const u8, perm: usize) usize {
+ return syscall2(SYS_creat, @ptrToInt(path), perm);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
+ // dirfd could be negative, for example AT_FDCWD is -100
+ return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
+}
+
+/// See also `clone` (from the arch-specific include)
+pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
+ return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
+}
+
+/// See also `clone` (from the arch-specific include)
+pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
+ return syscall2(SYS_clone, flags, child_stack_ptr);
+}
+
+pub fn close(fd: i32) usize {
+ return syscall1(SYS_close, @bitCast(usize, isize(fd)));
+}
+
+pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
+ return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
+}
+
+pub fn exit(status: i32) noreturn {
+ _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
+ unreachable;
+}
+
+pub fn exit_group(status: i32) noreturn {
+ _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status)));
+ unreachable;
+}
+
+pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
+ return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags);
+}
+
+pub fn kill(pid: i32, sig: i32) usize {
+ return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn unlink(path: [*]const u8) usize {
+ return unlinkat(AT_FDCWD, path, 0);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
+ return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
+}
+
+pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
+ return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
+}
+
+pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
+ if (VDSO_CGT_SYM.len != 0) {
+ const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
+ if (@ptrToInt(f) != 0) {
+ const rc = f(clk_id, tp);
+ switch (rc) {
+ 0, @bitCast(usize, isize(-EINVAL)) => return rc,
+ else => {},
+ }
+ }
+ }
+ return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
+}
+var vdso_clock_gettime = init_vdso_clock_gettime;
+extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
+ const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
+ var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
+ _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
+ if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
+ return f(clk, ts);
+}
+
+pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
+ return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
+}
+
+pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
+ return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
+}
+
+pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
+ return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
+}
+
+pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
+ return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
+}
+
+pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
+ return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
+}
+
+pub fn setuid(uid: u32) usize {
+ return syscall1(SYS_setuid, uid);
+}
+
+pub fn setgid(gid: u32) usize {
+ return syscall1(SYS_setgid, gid);
+}
+
+pub fn setreuid(ruid: u32, euid: u32) usize {
+ return syscall2(SYS_setreuid, ruid, euid);
+}
+
+pub fn setregid(rgid: u32, egid: u32) usize {
+ return syscall2(SYS_setregid, rgid, egid);
+}
+
+pub fn getuid() u32 {
+ return u32(syscall0(SYS_getuid));
+}
+
+pub fn getgid() u32 {
+ return u32(syscall0(SYS_getgid));
+}
+
+pub fn geteuid() u32 {
+ return u32(syscall0(SYS_geteuid));
+}
+
+pub fn getegid() u32 {
+ return u32(syscall0(SYS_getegid));
+}
+
+pub fn seteuid(euid: u32) usize {
+ return syscall1(SYS_seteuid, euid);
+}
+
+pub fn setegid(egid: u32) usize {
+ return syscall1(SYS_setegid, egid);
+}
+
+pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
+ return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
+}
+
+pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
+ return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
+}
+
+pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
+ return syscall3(SYS_setresuid, ruid, euid, suid);
+}
+
+pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
+ return syscall3(SYS_setresgid, rgid, egid, sgid);
+}
+
+pub fn getgroups(size: usize, list: *u32) usize {
+ return syscall2(SYS_getgroups, size, @ptrToInt(list));
+}
+
+pub fn setgroups(size: usize, list: *const u32) usize {
+ return syscall2(SYS_setgroups, size, @ptrToInt(list));
+}
+
+pub fn getpid() i32 {
+ return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
+}
+
+pub fn gettid() i32 {
+ return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
+}
+
+pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
+ return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
+}
+
+pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
+ assert(sig >= 1);
+ assert(sig != SIGKILL);
+ assert(sig != SIGSTOP);
+ var ksa = k_sigaction{
+ .handler = act.handler,
+ .flags = act.flags | SA_RESTORER,
+ .mask = undefined,
+ .restorer = @ptrCast(extern fn () void, restore_rt),
+ };
+ var ksa_old: k_sigaction = undefined;
+ @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
+ const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
+ const err = getErrno(result);
+ if (err != 0) {
+ return result;
+ }
+ if (oact) |old| {
+ old.handler = ksa_old.handler;
+ old.flags = @truncate(u32, ksa_old.flags);
+ @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
+ }
+ return 0;
+}
+
+const NSIG = 65;
+const sigset_t = [128 / @sizeOf(usize)]usize;
+const all_mask = []usize{maxInt(usize)};
+const app_mask = []usize{0xfffffffc7fffffff};
+
+const k_sigaction = extern struct {
+ handler: extern fn (i32) void,
+ flags: usize,
+ restorer: extern fn () void,
+ mask: [2]u32,
+};
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = struct {
+ handler: extern fn (i32) void,
+ mask: sigset_t,
+ flags: u32,
+};
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+pub const empty_sigset = []usize{0} ** sigset_t.len;
+
+pub fn raise(sig: i32) usize {
+ var set: sigset_t = undefined;
+ blockAppSignals(&set);
+ const tid = syscall0(SYS_gettid);
+ const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
+ restoreSignals(&set);
+ return ret;
+}
+
+fn blockAllSignals(set: *sigset_t) void {
+ _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
+}
+
+fn blockAppSignals(set: *sigset_t) void {
+ _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
+}
+
+fn restoreSignals(set: *sigset_t) void {
+ _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
+}
+
+pub fn sigaddset(set: *sigset_t, sig: u6) void {
+ const s = sig - 1;
+ (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
+}
+
+pub fn sigismember(set: *const sigset_t, sig: u6) bool {
+ const s = sig - 1;
+ return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
+}
+
+pub const in_port_t = u16;
+pub const sa_family_t = u16;
+pub const socklen_t = u32;
+
+/// This intentionally only has ip4 and ip6
+pub const sockaddr = extern union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+};
+
+pub const sockaddr_in = extern struct {
+ family: sa_family_t,
+ port: in_port_t,
+ addr: u32,
+ zero: [8]u8,
+};
+
+pub const sockaddr_in6 = extern struct {
+ family: sa_family_t,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: [16]u8,
+ scope_id: u32,
+};
+
+pub const sockaddr_un = extern struct {
+ family: sa_family_t,
+ path: [108]u8,
+};
+
+pub const iovec = extern struct {
+ iov_base: [*]u8,
+ iov_len: usize,
+};
+
+pub const iovec_const = extern struct {
+ iov_base: [*]const u8,
+ iov_len: usize,
+};
+
+pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
+ return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
+}
+
+pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
+ return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
+}
+
+pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
+ return syscall3(SYS_socket, domain, socket_type, protocol);
+}
+
+pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
+ return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
+}
+
+pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
+ return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
+}
+
+pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
+ return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
+}
+
+pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
+ return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
+}
+
+pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
+ return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
+}
+
+pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
+ return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
+}
+
+pub fn shutdown(fd: i32, how: i32) usize {
+ return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
+}
+
+pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
+ return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
+}
+
+pub fn listen(fd: i32, backlog: u32) usize {
+ return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
+}
+
+pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
+ return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
+}
+
+pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
+ return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
+}
+
+pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
+ return accept4(fd, addr, len, 0);
+}
+
+pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
+ return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
+}
+
+pub fn fstat(fd: i32, stat_buf: *Stat) usize {
+ return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
+ return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
+ return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
+ return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
+ return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
+ return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
+}
+
+pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
+ return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
+ return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
+ return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
+ return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
+ return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
+ return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
+ return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
+ return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
+ return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
+}
+
+// TODO https://github.com/ziglang/zig/issues/265
+pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
+ return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
+}
+
+pub fn sched_getaffinity(pid: i32, set: []usize) usize {
+ return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
+}
+
+pub const epoll_data = packed union {
+ ptr: usize,
+ fd: i32,
+ @"u32": u32,
+ @"u64": u64,
+};
+
+pub const epoll_event = packed struct {
+ events: u32,
+ data: epoll_data,
+};
+
+pub fn epoll_create() usize {
+ return epoll_create1(0);
+}
+
+pub fn epoll_create1(flags: usize) usize {
+ return syscall1(SYS_epoll_create1, flags);
+}
+
+pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
+ return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
+}
+
+pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
+ return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
+}
+
+pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
+ return syscall6(
+ SYS_epoll_pwait,
+ @bitCast(usize, isize(epoll_fd)),
+ @ptrToInt(events),
+ @intCast(usize, maxevents),
+ @bitCast(usize, isize(timeout)),
+ @ptrToInt(sigmask),
+ @sizeOf(sigset_t),
+ );
+}
+
+pub fn eventfd(count: u32, flags: u32) usize {
+ return syscall2(SYS_eventfd2, count, flags);
+}
+
+pub fn timerfd_create(clockid: i32, flags: u32) usize {
+ return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
+}
+
+pub const itimerspec = extern struct {
+ it_interval: timespec,
+ it_value: timespec,
+};
+
+pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
+ return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
+}
+
+pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
+ return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
+}
+
+pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
+pub const _LINUX_CAPABILITY_U32S_1 = 1;
+
+pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
+pub const _LINUX_CAPABILITY_U32S_2 = 2;
+
+pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
+pub const _LINUX_CAPABILITY_U32S_3 = 2;
+
+pub const VFS_CAP_REVISION_MASK = 0xFF000000;
+pub const VFS_CAP_REVISION_SHIFT = 24;
+pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
+pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
+
+pub const VFS_CAP_REVISION_1 = 0x01000000;
+pub const VFS_CAP_U32_1 = 1;
+pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
+
+pub const VFS_CAP_REVISION_2 = 0x02000000;
+pub const VFS_CAP_U32_2 = 2;
+pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
+
+pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
+pub const VFS_CAP_U32 = VFS_CAP_U32_2;
+pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
+
+pub const vfs_cap_data = extern struct {
+ //all of these are mandated as little endian
+ //when on disk.
+ const Data = struct {
+ permitted: u32,
+ inheritable: u32,
+ };
+
+ magic_etc: u32,
+ data: [VFS_CAP_U32]Data,
+};
+
+pub const CAP_CHOWN = 0;
+pub const CAP_DAC_OVERRIDE = 1;
+pub const CAP_DAC_READ_SEARCH = 2;
+pub const CAP_FOWNER = 3;
+pub const CAP_FSETID = 4;
+pub const CAP_KILL = 5;
+pub const CAP_SETGID = 6;
+pub const CAP_SETUID = 7;
+pub const CAP_SETPCAP = 8;
+pub const CAP_LINUX_IMMUTABLE = 9;
+pub const CAP_NET_BIND_SERVICE = 10;
+pub const CAP_NET_BROADCAST = 11;
+pub const CAP_NET_ADMIN = 12;
+pub const CAP_NET_RAW = 13;
+pub const CAP_IPC_LOCK = 14;
+pub const CAP_IPC_OWNER = 15;
+pub const CAP_SYS_MODULE = 16;
+pub const CAP_SYS_RAWIO = 17;
+pub const CAP_SYS_CHROOT = 18;
+pub const CAP_SYS_PTRACE = 19;
+pub const CAP_SYS_PACCT = 20;
+pub const CAP_SYS_ADMIN = 21;
+pub const CAP_SYS_BOOT = 22;
+pub const CAP_SYS_NICE = 23;
+pub const CAP_SYS_RESOURCE = 24;
+pub const CAP_SYS_TIME = 25;
+pub const CAP_SYS_TTY_CONFIG = 26;
+pub const CAP_MKNOD = 27;
+pub const CAP_LEASE = 28;
+pub const CAP_AUDIT_WRITE = 29;
+pub const CAP_AUDIT_CONTROL = 30;
+pub const CAP_SETFCAP = 31;
+pub const CAP_MAC_OVERRIDE = 32;
+pub const CAP_MAC_ADMIN = 33;
+pub const CAP_SYSLOG = 34;
+pub const CAP_WAKE_ALARM = 35;
+pub const CAP_BLOCK_SUSPEND = 36;
+pub const CAP_AUDIT_READ = 37;
+pub const CAP_LAST_CAP = CAP_AUDIT_READ;
+
+pub fn cap_valid(u8: x) bool {
+ return x >= 0 and x <= CAP_LAST_CAP;
+}
+
+pub fn CAP_TO_MASK(cap: u8) u32 {
+ return u32(1) << u5(cap & 31);
+}
+
+pub fn CAP_TO_INDEX(cap: u8) u8 {
+ return cap >> 5;
+}
+
+pub const cap_t = extern struct {
+ hdrp: *cap_user_header_t,
+ datap: *cap_user_data_t,
+};
+
+pub const cap_user_header_t = extern struct {
+ version: u32,
+ pid: usize,
+};
+
+pub const cap_user_data_t = extern struct {
+ effective: u32,
+ permitted: u32,
+ inheritable: u32,
+};
+
+pub fn unshare(flags: usize) usize {
+ return syscall1(SYS_unshare, flags);
+}
+
+pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
+ return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
+}
+
+pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
+ return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
+}
+
+pub const inotify_event = extern struct {
+ wd: i32,
+ mask: u32,
+ cookie: u32,
+ len: u32,
+ //name: [?]u8,
+};
+
+pub const dirent64 = extern struct {
+ d_ino: u64,
+ d_off: u64,
+ d_reclen: u16,
+ d_type: u8,
+ d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
+};
+
+test "import" {
+ if (builtin.os == builtin.Os.linux) {
+ _ = @import("linux/test.zig");
+ }
+}
diff --git a/std/os/linux/arm64.zig b/std/os/linux/arm64.zig
index 91e4a496796522c5d878d761d5649fcedd6548aa..ac2c18ee5f2abf19081940c47b4d6252b45ce952 100644
--- a/std/os/linux/arm64.zig
+++ b/std/os/linux/arm64.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
const iovec = linux.iovec;
diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig
deleted file mode 100644
index b78c1b3da5d271a811fb7216571d3d6fbbb93f9f..0000000000000000000000000000000000000000
--- a/std/os/linux/index.zig
+++ /dev/null
@@ -1,1537 +0,0 @@
-const std = @import("../../index.zig");
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-const vdso = @import("vdso.zig");
-pub use switch (builtin.arch) {
- builtin.Arch.x86_64 => @import("x86_64.zig"),
- builtin.Arch.i386 => @import("i386.zig"),
- builtin.Arch.aarch64 => @import("arm64.zig"),
- else => @compileError("unsupported arch"),
-};
-pub use @import("errno.zig");
-
-pub const PATH_MAX = 4096;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const FUTEX_WAIT = 0;
-pub const FUTEX_WAKE = 1;
-pub const FUTEX_FD = 2;
-pub const FUTEX_REQUEUE = 3;
-pub const FUTEX_CMP_REQUEUE = 4;
-pub const FUTEX_WAKE_OP = 5;
-pub const FUTEX_LOCK_PI = 6;
-pub const FUTEX_UNLOCK_PI = 7;
-pub const FUTEX_TRYLOCK_PI = 8;
-pub const FUTEX_WAIT_BITSET = 9;
-
-pub const FUTEX_PRIVATE_FLAG = 128;
-
-pub const FUTEX_CLOCK_REALTIME = 256;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-pub const PROT_GROWSDOWN = 0x01000000;
-pub const PROT_GROWSUP = 0x02000000;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x01;
-pub const MAP_PRIVATE = 0x02;
-pub const MAP_TYPE = 0x0f;
-pub const MAP_FIXED = 0x10;
-pub const MAP_ANONYMOUS = 0x20;
-pub const MAP_NORESERVE = 0x4000;
-pub const MAP_GROWSDOWN = 0x0100;
-pub const MAP_DENYWRITE = 0x0800;
-pub const MAP_EXECUTABLE = 0x1000;
-pub const MAP_LOCKED = 0x2000;
-pub const MAP_POPULATE = 0x8000;
-pub const MAP_NONBLOCK = 0x10000;
-pub const MAP_STACK = 0x20000;
-pub const MAP_HUGETLB = 0x40000;
-pub const MAP_FILE = 0;
-
-pub const F_OK = 0;
-pub const X_OK = 1;
-pub const W_OK = 2;
-pub const R_OK = 4;
-
-pub const WNOHANG = 1;
-pub const WUNTRACED = 2;
-pub const WSTOPPED = 2;
-pub const WEXITED = 4;
-pub const WCONTINUED = 8;
-pub const WNOWAIT = 0x1000000;
-
-pub const SA_NOCLDSTOP = 1;
-pub const SA_NOCLDWAIT = 2;
-pub const SA_SIGINFO = 4;
-pub const SA_ONSTACK = 0x08000000;
-pub const SA_RESTART = 0x10000000;
-pub const SA_NODEFER = 0x40000000;
-pub const SA_RESETHAND = 0x80000000;
-pub const SA_RESTORER = 0x04000000;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGBUS = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGUSR1 = 10;
-pub const SIGSEGV = 11;
-pub const SIGUSR2 = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGSTKFLT = 16;
-pub const SIGCHLD = 17;
-pub const SIGCONT = 18;
-pub const SIGSTOP = 19;
-pub const SIGTSTP = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGURG = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGIO = 29;
-pub const SIGPOLL = 29;
-pub const SIGPWR = 30;
-pub const SIGSYS = 31;
-pub const SIGUNUSED = SIGSYS;
-
-pub const O_RDONLY = 0o0;
-pub const O_WRONLY = 0o1;
-pub const O_RDWR = 0o2;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 0;
-pub const SIG_UNBLOCK = 1;
-pub const SIG_SETMASK = 2;
-
-pub const PROTO_ip = 0o000;
-pub const PROTO_icmp = 0o001;
-pub const PROTO_igmp = 0o002;
-pub const PROTO_ggp = 0o003;
-pub const PROTO_ipencap = 0o004;
-pub const PROTO_st = 0o005;
-pub const PROTO_tcp = 0o006;
-pub const PROTO_egp = 0o010;
-pub const PROTO_pup = 0o014;
-pub const PROTO_udp = 0o021;
-pub const PROTO_hmp = 0o024;
-pub const PROTO_xns_idp = 0o026;
-pub const PROTO_rdp = 0o033;
-pub const PROTO_iso_tp4 = 0o035;
-pub const PROTO_xtp = 0o044;
-pub const PROTO_ddp = 0o045;
-pub const PROTO_idpr_cmtp = 0o046;
-pub const PROTO_ipv6 = 0o051;
-pub const PROTO_ipv6_route = 0o053;
-pub const PROTO_ipv6_frag = 0o054;
-pub const PROTO_idrp = 0o055;
-pub const PROTO_rsvp = 0o056;
-pub const PROTO_gre = 0o057;
-pub const PROTO_esp = 0o062;
-pub const PROTO_ah = 0o063;
-pub const PROTO_skip = 0o071;
-pub const PROTO_ipv6_icmp = 0o072;
-pub const PROTO_ipv6_nonxt = 0o073;
-pub const PROTO_ipv6_opts = 0o074;
-pub const PROTO_rspf = 0o111;
-pub const PROTO_vmtp = 0o121;
-pub const PROTO_ospf = 0o131;
-pub const PROTO_ipip = 0o136;
-pub const PROTO_encap = 0o142;
-pub const PROTO_pim = 0o147;
-pub const PROTO_raw = 0o377;
-
-pub const SHUT_RD = 0;
-pub const SHUT_WR = 1;
-pub const SHUT_RDWR = 2;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-pub const SOCK_DCCP = 6;
-pub const SOCK_PACKET = 10;
-pub const SOCK_CLOEXEC = 0o2000000;
-pub const SOCK_NONBLOCK = 0o4000;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_AX25 = 3;
-pub const PF_IPX = 4;
-pub const PF_APPLETALK = 5;
-pub const PF_NETROM = 6;
-pub const PF_BRIDGE = 7;
-pub const PF_ATMPVC = 8;
-pub const PF_X25 = 9;
-pub const PF_INET6 = 10;
-pub const PF_ROSE = 11;
-pub const PF_DECnet = 12;
-pub const PF_NETBEUI = 13;
-pub const PF_SECURITY = 14;
-pub const PF_KEY = 15;
-pub const PF_NETLINK = 16;
-pub const PF_ROUTE = PF_NETLINK;
-pub const PF_PACKET = 17;
-pub const PF_ASH = 18;
-pub const PF_ECONET = 19;
-pub const PF_ATMSVC = 20;
-pub const PF_RDS = 21;
-pub const PF_SNA = 22;
-pub const PF_IRDA = 23;
-pub const PF_PPPOX = 24;
-pub const PF_WANPIPE = 25;
-pub const PF_LLC = 26;
-pub const PF_IB = 27;
-pub const PF_MPLS = 28;
-pub const PF_CAN = 29;
-pub const PF_TIPC = 30;
-pub const PF_BLUETOOTH = 31;
-pub const PF_IUCV = 32;
-pub const PF_RXRPC = 33;
-pub const PF_ISDN = 34;
-pub const PF_PHONET = 35;
-pub const PF_IEEE802154 = 36;
-pub const PF_CAIF = 37;
-pub const PF_ALG = 38;
-pub const PF_NFC = 39;
-pub const PF_VSOCK = 40;
-pub const PF_KCM = 41;
-pub const PF_QIPCRTR = 42;
-pub const PF_SMC = 43;
-pub const PF_MAX = 44;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_AX25 = PF_AX25;
-pub const AF_IPX = PF_IPX;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_NETROM = PF_NETROM;
-pub const AF_BRIDGE = PF_BRIDGE;
-pub const AF_ATMPVC = PF_ATMPVC;
-pub const AF_X25 = PF_X25;
-pub const AF_INET6 = PF_INET6;
-pub const AF_ROSE = PF_ROSE;
-pub const AF_DECnet = PF_DECnet;
-pub const AF_NETBEUI = PF_NETBEUI;
-pub const AF_SECURITY = PF_SECURITY;
-pub const AF_KEY = PF_KEY;
-pub const AF_NETLINK = PF_NETLINK;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_PACKET = PF_PACKET;
-pub const AF_ASH = PF_ASH;
-pub const AF_ECONET = PF_ECONET;
-pub const AF_ATMSVC = PF_ATMSVC;
-pub const AF_RDS = PF_RDS;
-pub const AF_SNA = PF_SNA;
-pub const AF_IRDA = PF_IRDA;
-pub const AF_PPPOX = PF_PPPOX;
-pub const AF_WANPIPE = PF_WANPIPE;
-pub const AF_LLC = PF_LLC;
-pub const AF_IB = PF_IB;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_TIPC = PF_TIPC;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_IUCV = PF_IUCV;
-pub const AF_RXRPC = PF_RXRPC;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_PHONET = PF_PHONET;
-pub const AF_IEEE802154 = PF_IEEE802154;
-pub const AF_CAIF = PF_CAIF;
-pub const AF_ALG = PF_ALG;
-pub const AF_NFC = PF_NFC;
-pub const AF_VSOCK = PF_VSOCK;
-pub const AF_KCM = PF_KCM;
-pub const AF_QIPCRTR = PF_QIPCRTR;
-pub const AF_SMC = PF_SMC;
-pub const AF_MAX = PF_MAX;
-
-pub const SO_DEBUG = 1;
-pub const SO_REUSEADDR = 2;
-pub const SO_TYPE = 3;
-pub const SO_ERROR = 4;
-pub const SO_DONTROUTE = 5;
-pub const SO_BROADCAST = 6;
-pub const SO_SNDBUF = 7;
-pub const SO_RCVBUF = 8;
-pub const SO_KEEPALIVE = 9;
-pub const SO_OOBINLINE = 10;
-pub const SO_NO_CHECK = 11;
-pub const SO_PRIORITY = 12;
-pub const SO_LINGER = 13;
-pub const SO_BSDCOMPAT = 14;
-pub const SO_REUSEPORT = 15;
-pub const SO_PASSCRED = 16;
-pub const SO_PEERCRED = 17;
-pub const SO_RCVLOWAT = 18;
-pub const SO_SNDLOWAT = 19;
-pub const SO_RCVTIMEO = 20;
-pub const SO_SNDTIMEO = 21;
-pub const SO_ACCEPTCONN = 30;
-pub const SO_SNDBUFFORCE = 32;
-pub const SO_RCVBUFFORCE = 33;
-pub const SO_PROTOCOL = 38;
-pub const SO_DOMAIN = 39;
-
-pub const SO_SECURITY_AUTHENTICATION = 22;
-pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
-pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
-
-pub const SO_BINDTODEVICE = 25;
-
-pub const SO_ATTACH_FILTER = 26;
-pub const SO_DETACH_FILTER = 27;
-pub const SO_GET_FILTER = SO_ATTACH_FILTER;
-
-pub const SO_PEERNAME = 28;
-pub const SO_TIMESTAMP = 29;
-pub const SCM_TIMESTAMP = SO_TIMESTAMP;
-
-pub const SO_PEERSEC = 31;
-pub const SO_PASSSEC = 34;
-pub const SO_TIMESTAMPNS = 35;
-pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
-pub const SO_MARK = 36;
-pub const SO_TIMESTAMPING = 37;
-pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
-pub const SO_RXQ_OVFL = 40;
-pub const SO_WIFI_STATUS = 41;
-pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
-pub const SO_PEEK_OFF = 42;
-pub const SO_NOFCS = 43;
-pub const SO_LOCK_FILTER = 44;
-pub const SO_SELECT_ERR_QUEUE = 45;
-pub const SO_BUSY_POLL = 46;
-pub const SO_MAX_PACING_RATE = 47;
-pub const SO_BPF_EXTENSIONS = 48;
-pub const SO_INCOMING_CPU = 49;
-pub const SO_ATTACH_BPF = 50;
-pub const SO_DETACH_BPF = SO_DETACH_FILTER;
-pub const SO_ATTACH_REUSEPORT_CBPF = 51;
-pub const SO_ATTACH_REUSEPORT_EBPF = 52;
-pub const SO_CNX_ADVICE = 53;
-pub const SCM_TIMESTAMPING_OPT_STATS = 54;
-pub const SO_MEMINFO = 55;
-pub const SO_INCOMING_NAPI_ID = 56;
-pub const SO_COOKIE = 57;
-pub const SCM_TIMESTAMPING_PKTINFO = 58;
-pub const SO_PEERGROUPS = 59;
-pub const SO_ZEROCOPY = 60;
-
-pub const SOL_SOCKET = 1;
-
-pub const SOL_IP = 0;
-pub const SOL_IPV6 = 41;
-pub const SOL_ICMPV6 = 58;
-
-pub const SOL_RAW = 255;
-pub const SOL_DECNET = 261;
-pub const SOL_X25 = 262;
-pub const SOL_PACKET = 263;
-pub const SOL_ATM = 264;
-pub const SOL_AAL = 265;
-pub const SOL_IRDA = 266;
-pub const SOL_NETBEUI = 267;
-pub const SOL_LLC = 268;
-pub const SOL_DCCP = 269;
-pub const SOL_NETLINK = 270;
-pub const SOL_TIPC = 271;
-pub const SOL_RXRPC = 272;
-pub const SOL_PPPOL2TP = 273;
-pub const SOL_BLUETOOTH = 274;
-pub const SOL_PNPIPE = 275;
-pub const SOL_RDS = 276;
-pub const SOL_IUCV = 277;
-pub const SOL_CAIF = 278;
-pub const SOL_ALG = 279;
-pub const SOL_NFC = 280;
-pub const SOL_KCM = 281;
-pub const SOL_TLS = 282;
-
-pub const SOMAXCONN = 128;
-
-pub const MSG_OOB = 0x0001;
-pub const MSG_PEEK = 0x0002;
-pub const MSG_DONTROUTE = 0x0004;
-pub const MSG_CTRUNC = 0x0008;
-pub const MSG_PROXY = 0x0010;
-pub const MSG_TRUNC = 0x0020;
-pub const MSG_DONTWAIT = 0x0040;
-pub const MSG_EOR = 0x0080;
-pub const MSG_WAITALL = 0x0100;
-pub const MSG_FIN = 0x0200;
-pub const MSG_SYN = 0x0400;
-pub const MSG_CONFIRM = 0x0800;
-pub const MSG_RST = 0x1000;
-pub const MSG_ERRQUEUE = 0x2000;
-pub const MSG_NOSIGNAL = 0x4000;
-pub const MSG_MORE = 0x8000;
-pub const MSG_WAITFORONE = 0x10000;
-pub const MSG_BATCH = 0x40000;
-pub const MSG_ZEROCOPY = 0x4000000;
-pub const MSG_FASTOPEN = 0x20000000;
-pub const MSG_CMSG_CLOEXEC = 0x40000000;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-pub const TCGETS = 0x5401;
-pub const TCSETS = 0x5402;
-pub const TCSETSW = 0x5403;
-pub const TCSETSF = 0x5404;
-pub const TCGETA = 0x5405;
-pub const TCSETA = 0x5406;
-pub const TCSETAW = 0x5407;
-pub const TCSETAF = 0x5408;
-pub const TCSBRK = 0x5409;
-pub const TCXONC = 0x540A;
-pub const TCFLSH = 0x540B;
-pub const TIOCEXCL = 0x540C;
-pub const TIOCNXCL = 0x540D;
-pub const TIOCSCTTY = 0x540E;
-pub const TIOCGPGRP = 0x540F;
-pub const TIOCSPGRP = 0x5410;
-pub const TIOCOUTQ = 0x5411;
-pub const TIOCSTI = 0x5412;
-pub const TIOCGWINSZ = 0x5413;
-pub const TIOCSWINSZ = 0x5414;
-pub const TIOCMGET = 0x5415;
-pub const TIOCMBIS = 0x5416;
-pub const TIOCMBIC = 0x5417;
-pub const TIOCMSET = 0x5418;
-pub const TIOCGSOFTCAR = 0x5419;
-pub const TIOCSSOFTCAR = 0x541A;
-pub const FIONREAD = 0x541B;
-pub const TIOCINQ = FIONREAD;
-pub const TIOCLINUX = 0x541C;
-pub const TIOCCONS = 0x541D;
-pub const TIOCGSERIAL = 0x541E;
-pub const TIOCSSERIAL = 0x541F;
-pub const TIOCPKT = 0x5420;
-pub const FIONBIO = 0x5421;
-pub const TIOCNOTTY = 0x5422;
-pub const TIOCSETD = 0x5423;
-pub const TIOCGETD = 0x5424;
-pub const TCSBRKP = 0x5425;
-pub const TIOCSBRK = 0x5427;
-pub const TIOCCBRK = 0x5428;
-pub const TIOCGSID = 0x5429;
-pub const TIOCGRS485 = 0x542E;
-pub const TIOCSRS485 = 0x542F;
-pub const TIOCGPTN = 0x80045430;
-pub const TIOCSPTLCK = 0x40045431;
-pub const TIOCGDEV = 0x80045432;
-pub const TCGETX = 0x5432;
-pub const TCSETX = 0x5433;
-pub const TCSETXF = 0x5434;
-pub const TCSETXW = 0x5435;
-pub const TIOCSIG = 0x40045436;
-pub const TIOCVHANGUP = 0x5437;
-pub const TIOCGPKT = 0x80045438;
-pub const TIOCGPTLCK = 0x80045439;
-pub const TIOCGEXCL = 0x80045440;
-
-pub const EPOLL_CLOEXEC = O_CLOEXEC;
-
-pub const EPOLL_CTL_ADD = 1;
-pub const EPOLL_CTL_DEL = 2;
-pub const EPOLL_CTL_MOD = 3;
-
-pub const EPOLLIN = 0x001;
-pub const EPOLLPRI = 0x002;
-pub const EPOLLOUT = 0x004;
-pub const EPOLLRDNORM = 0x040;
-pub const EPOLLRDBAND = 0x080;
-pub const EPOLLWRNORM = 0x100;
-pub const EPOLLWRBAND = 0x200;
-pub const EPOLLMSG = 0x400;
-pub const EPOLLERR = 0x008;
-pub const EPOLLHUP = 0x010;
-pub const EPOLLRDHUP = 0x2000;
-pub const EPOLLEXCLUSIVE = (u32(1) << 28);
-pub const EPOLLWAKEUP = (u32(1) << 29);
-pub const EPOLLONESHOT = (u32(1) << 30);
-pub const EPOLLET = (u32(1) << 31);
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_MONOTONIC = 1;
-pub const CLOCK_PROCESS_CPUTIME_ID = 2;
-pub const CLOCK_THREAD_CPUTIME_ID = 3;
-pub const CLOCK_MONOTONIC_RAW = 4;
-pub const CLOCK_REALTIME_COARSE = 5;
-pub const CLOCK_MONOTONIC_COARSE = 6;
-pub const CLOCK_BOOTTIME = 7;
-pub const CLOCK_REALTIME_ALARM = 8;
-pub const CLOCK_BOOTTIME_ALARM = 9;
-pub const CLOCK_SGI_CYCLE = 10;
-pub const CLOCK_TAI = 11;
-
-pub const CSIGNAL = 0x000000ff;
-pub const CLONE_VM = 0x00000100;
-pub const CLONE_FS = 0x00000200;
-pub const CLONE_FILES = 0x00000400;
-pub const CLONE_SIGHAND = 0x00000800;
-pub const CLONE_PTRACE = 0x00002000;
-pub const CLONE_VFORK = 0x00004000;
-pub const CLONE_PARENT = 0x00008000;
-pub const CLONE_THREAD = 0x00010000;
-pub const CLONE_NEWNS = 0x00020000;
-pub const CLONE_SYSVSEM = 0x00040000;
-pub const CLONE_SETTLS = 0x00080000;
-pub const CLONE_PARENT_SETTID = 0x00100000;
-pub const CLONE_CHILD_CLEARTID = 0x00200000;
-pub const CLONE_DETACHED = 0x00400000;
-pub const CLONE_UNTRACED = 0x00800000;
-pub const CLONE_CHILD_SETTID = 0x01000000;
-pub const CLONE_NEWCGROUP = 0x02000000;
-pub const CLONE_NEWUTS = 0x04000000;
-pub const CLONE_NEWIPC = 0x08000000;
-pub const CLONE_NEWUSER = 0x10000000;
-pub const CLONE_NEWPID = 0x20000000;
-pub const CLONE_NEWNET = 0x40000000;
-pub const CLONE_IO = 0x80000000;
-
-pub const EFD_SEMAPHORE = 1;
-pub const EFD_CLOEXEC = O_CLOEXEC;
-pub const EFD_NONBLOCK = O_NONBLOCK;
-
-pub const MS_RDONLY = 1;
-pub const MS_NOSUID = 2;
-pub const MS_NODEV = 4;
-pub const MS_NOEXEC = 8;
-pub const MS_SYNCHRONOUS = 16;
-pub const MS_REMOUNT = 32;
-pub const MS_MANDLOCK = 64;
-pub const MS_DIRSYNC = 128;
-pub const MS_NOATIME = 1024;
-pub const MS_NODIRATIME = 2048;
-pub const MS_BIND = 4096;
-pub const MS_MOVE = 8192;
-pub const MS_REC = 16384;
-pub const MS_SILENT = 32768;
-pub const MS_POSIXACL = (1 << 16);
-pub const MS_UNBINDABLE = (1 << 17);
-pub const MS_PRIVATE = (1 << 18);
-pub const MS_SLAVE = (1 << 19);
-pub const MS_SHARED = (1 << 20);
-pub const MS_RELATIME = (1 << 21);
-pub const MS_KERNMOUNT = (1 << 22);
-pub const MS_I_VERSION = (1 << 23);
-pub const MS_STRICTATIME = (1 << 24);
-pub const MS_LAZYTIME = (1 << 25);
-pub const MS_NOREMOTELOCK = (1 << 27);
-pub const MS_NOSEC = (1 << 28);
-pub const MS_BORN = (1 << 29);
-pub const MS_ACTIVE = (1 << 30);
-pub const MS_NOUSER = (1 << 31);
-
-pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
-
-pub const MS_MGC_VAL = 0xc0ed0000;
-pub const MS_MGC_MSK = 0xffff0000;
-
-pub const MNT_FORCE = 1;
-pub const MNT_DETACH = 2;
-pub const MNT_EXPIRE = 4;
-pub const UMOUNT_NOFOLLOW = 8;
-
-pub const IN_CLOEXEC = O_CLOEXEC;
-pub const IN_NONBLOCK = O_NONBLOCK;
-
-pub const IN_ACCESS = 0x00000001;
-pub const IN_MODIFY = 0x00000002;
-pub const IN_ATTRIB = 0x00000004;
-pub const IN_CLOSE_WRITE = 0x00000008;
-pub const IN_CLOSE_NOWRITE = 0x00000010;
-pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
-pub const IN_OPEN = 0x00000020;
-pub const IN_MOVED_FROM = 0x00000040;
-pub const IN_MOVED_TO = 0x00000080;
-pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
-pub const IN_CREATE = 0x00000100;
-pub const IN_DELETE = 0x00000200;
-pub const IN_DELETE_SELF = 0x00000400;
-pub const IN_MOVE_SELF = 0x00000800;
-pub const IN_ALL_EVENTS = 0x00000fff;
-
-pub const IN_UNMOUNT = 0x00002000;
-pub const IN_Q_OVERFLOW = 0x00004000;
-pub const IN_IGNORED = 0x00008000;
-
-pub const IN_ONLYDIR = 0x01000000;
-pub const IN_DONT_FOLLOW = 0x02000000;
-pub const IN_EXCL_UNLINK = 0x04000000;
-pub const IN_MASK_ADD = 0x20000000;
-
-pub const IN_ISDIR = 0x40000000;
-pub const IN_ONESHOT = 0x80000000;
-
-pub const S_IFMT = 0o170000;
-
-pub const S_IFDIR = 0o040000;
-pub const S_IFCHR = 0o020000;
-pub const S_IFBLK = 0o060000;
-pub const S_IFREG = 0o100000;
-pub const S_IFIFO = 0o010000;
-pub const S_IFLNK = 0o120000;
-pub const S_IFSOCK = 0o140000;
-
-pub const S_ISUID = 0o4000;
-pub const S_ISGID = 0o2000;
-pub const S_ISVTX = 0o1000;
-pub const S_IRUSR = 0o400;
-pub const S_IWUSR = 0o200;
-pub const S_IXUSR = 0o100;
-pub const S_IRWXU = 0o700;
-pub const S_IRGRP = 0o040;
-pub const S_IWGRP = 0o020;
-pub const S_IXGRP = 0o010;
-pub const S_IRWXG = 0o070;
-pub const S_IROTH = 0o004;
-pub const S_IWOTH = 0o002;
-pub const S_IXOTH = 0o001;
-pub const S_IRWXO = 0o007;
-
-pub fn S_ISREG(m: u32) bool {
- return m & S_IFMT == S_IFREG;
-}
-
-pub fn S_ISDIR(m: u32) bool {
- return m & S_IFMT == S_IFDIR;
-}
-
-pub fn S_ISCHR(m: u32) bool {
- return m & S_IFMT == S_IFCHR;
-}
-
-pub fn S_ISBLK(m: u32) bool {
- return m & S_IFMT == S_IFBLK;
-}
-
-pub fn S_ISFIFO(m: u32) bool {
- return m & S_IFMT == S_IFIFO;
-}
-
-pub fn S_ISLNK(m: u32) bool {
- return m & S_IFMT == S_IFLNK;
-}
-
-pub fn S_ISSOCK(m: u32) bool {
- return m & S_IFMT == S_IFSOCK;
-}
-
-pub const TFD_NONBLOCK = O_NONBLOCK;
-pub const TFD_CLOEXEC = O_CLOEXEC;
-
-pub const TFD_TIMER_ABSTIME = 1;
-pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
-
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) & 0xff00) >> 8);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-pub fn WIFSTOPPED(s: i32) bool {
- return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
-}
-pub fn WIFSIGNALED(s: i32) bool {
- return (unsigned(s) & 0xffff) -% 1 < 0xff;
-}
-
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return dup3(old, new, 0);
-}
-
-pub fn dup3(old: i32, new: i32, flags: u32) usize {
- return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn chdir(path: [*]const u8) usize {
- return syscall1(SYS_chdir, @ptrToInt(path));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn chroot(path: [*]const u8) usize {
- return syscall1(SYS_chroot, @ptrToInt(path));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
-}
-
-pub fn fork() usize {
- return clone2(SIGCHLD, 0);
-}
-
-/// This must be inline, and inline call the syscall function, because if the
-/// child does a return it will clobber the parent's stack.
-/// It is advised to avoid this function and use clone instead, because
-/// the compiler is not aware of how vfork affects control flow and you may
-/// see different results in optimized builds.
-pub inline fn vfork() usize {
- return @inlineCall(syscall0, SYS_vfork);
-}
-
-pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize {
- return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout));
-}
-
-pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize {
- return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return syscall2(SYS_getcwd, @ptrToInt(buf), size);
-}
-
-pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
- return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
-}
-
-pub fn inotify_init1(flags: u32) usize {
- return syscall1(SYS_inotify_init1, flags);
-}
-
-pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
- return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
-}
-
-pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
- return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
-}
-
-pub fn isatty(fd: i32) bool {
- var wsz: winsize = undefined;
- return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return mkdirat(AT_FDCWD, path, mode);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
- return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize {
- return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn umount(special: [*]const u8) usize {
- return syscall2(SYS_umount2, @ptrToInt(special), 0);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn umount2(special: [*]const u8, flags: u32) usize {
- return syscall2(SYS_umount2, @ptrToInt(special), flags);
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return syscall2(SYS_munmap, address, length);
-}
-
-pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
- return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
-}
-
-pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
- return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
-}
-
-pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
- return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
-}
-
-pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
- return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
-}
-
-pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
- return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn rmdir(path: [*]const u8) usize {
- return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return symlinkat(existing, AT_FDCWD, new);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
- return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
- return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn access(path: [*]const u8, mode: u32) usize {
- return faccessat(AT_FDCWD, path, mode);
-}
-
-pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
- return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
-}
-
-pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
-}
-
-pub fn pipe2(fd: *[2]i32, flags: u32) usize {
- return syscall2(SYS_pipe2, @ptrToInt(fd), flags);
-}
-
-pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
- return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
- return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
- return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
- return openat(AT_FDCWD, path, flags, perm);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn create(path: [*]const u8, perm: usize) usize {
- return syscall2(SYS_creat, @ptrToInt(path), perm);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
- // dirfd could be negative, for example AT_FDCWD is -100
- return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
-}
-
-/// See also `clone` (from the arch-specific include)
-pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize {
- return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls);
-}
-
-/// See also `clone` (from the arch-specific include)
-pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
- return syscall2(SYS_clone, flags, child_stack_ptr);
-}
-
-pub fn close(fd: i32) usize {
- return syscall1(SYS_close, @bitCast(usize, isize(fd)));
-}
-
-pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
- return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
-}
-
-pub fn exit(status: i32) noreturn {
- _ = syscall1(SYS_exit, @bitCast(usize, isize(status)));
- unreachable;
-}
-
-pub fn exit_group(status: i32) noreturn {
- _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status)));
- unreachable;
-}
-
-pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
- return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags);
-}
-
-pub fn kill(pid: i32, sig: i32) usize {
- return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn unlink(path: [*]const u8) usize {
- return unlinkat(AT_FDCWD, path, 0);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
- return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
- return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
-}
-
-pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
- if (VDSO_CGT_SYM.len != 0) {
- const f = @atomicLoad(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, builtin.AtomicOrder.Unordered);
- if (@ptrToInt(f) != 0) {
- const rc = f(clk_id, tp);
- switch (rc) {
- 0, @bitCast(usize, isize(-EINVAL)) => return rc,
- else => {},
- }
- }
- }
- return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
-}
-var vdso_clock_gettime = init_vdso_clock_gettime;
-extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize {
- const addr = vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM);
- var f = @intToPtr(@typeOf(init_vdso_clock_gettime), addr);
- _ = @cmpxchgStrong(@typeOf(init_vdso_clock_gettime), &vdso_clock_gettime, init_vdso_clock_gettime, f, builtin.AtomicOrder.Monotonic, builtin.AtomicOrder.Monotonic);
- if (@ptrToInt(f) == 0) return @bitCast(usize, isize(-ENOSYS));
- return f(clk, ts);
-}
-
-pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
- return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
-}
-
-pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
- return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
-}
-
-pub fn gettimeofday(tv: *timeval, tz: *timezone) usize {
- return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
-}
-
-pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
- return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
-}
-
-pub fn setuid(uid: u32) usize {
- return syscall1(SYS_setuid, uid);
-}
-
-pub fn setgid(gid: u32) usize {
- return syscall1(SYS_setgid, gid);
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return syscall2(SYS_setreuid, ruid, euid);
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return syscall2(SYS_setregid, rgid, egid);
-}
-
-pub fn getuid() u32 {
- return u32(syscall0(SYS_getuid));
-}
-
-pub fn getgid() u32 {
- return u32(syscall0(SYS_getgid));
-}
-
-pub fn geteuid() u32 {
- return u32(syscall0(SYS_geteuid));
-}
-
-pub fn getegid() u32 {
- return u32(syscall0(SYS_getegid));
-}
-
-pub fn seteuid(euid: u32) usize {
- return syscall1(SYS_seteuid, euid);
-}
-
-pub fn setegid(egid: u32) usize {
- return syscall1(SYS_setegid, egid);
-}
-
-pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize {
- return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid));
-}
-
-pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize {
- return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid));
-}
-
-pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize {
- return syscall3(SYS_setresuid, ruid, euid, suid);
-}
-
-pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize {
- return syscall3(SYS_setresgid, rgid, egid, sgid);
-}
-
-pub fn getgroups(size: usize, list: *u32) usize {
- return syscall2(SYS_getgroups, size, @ptrToInt(list));
-}
-
-pub fn setgroups(size: usize, list: *const u32) usize {
- return syscall2(SYS_setgroups, size, @ptrToInt(list));
-}
-
-pub fn getpid() i32 {
- return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid)));
-}
-
-pub fn gettid() i32 {
- return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid)));
-}
-
-pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
- return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8);
-}
-
-pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
- assert(sig >= 1);
- assert(sig != SIGKILL);
- assert(sig != SIGSTOP);
- var ksa = k_sigaction{
- .handler = act.handler,
- .flags = act.flags | SA_RESTORER,
- .mask = undefined,
- .restorer = @ptrCast(extern fn () void, restore_rt),
- };
- var ksa_old: k_sigaction = undefined;
- @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
- const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
- const err = getErrno(result);
- if (err != 0) {
- return result;
- }
- if (oact) |old| {
- old.handler = ksa_old.handler;
- old.flags = @truncate(u32, ksa_old.flags);
- @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
- }
- return 0;
-}
-
-const NSIG = 65;
-const sigset_t = [128 / @sizeOf(usize)]usize;
-const all_mask = []usize{maxInt(usize)};
-const app_mask = []usize{0xfffffffc7fffffff};
-
-const k_sigaction = extern struct {
- handler: extern fn (i32) void,
- flags: usize,
- restorer: extern fn () void,
- mask: [2]u32,
-};
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = struct {
- handler: extern fn (i32) void,
- mask: sigset_t,
- flags: u32,
-};
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-pub const empty_sigset = []usize{0} ** sigset_t.len;
-
-pub fn raise(sig: i32) usize {
- var set: sigset_t = undefined;
- blockAppSignals(&set);
- const tid = syscall0(SYS_gettid);
- const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
- restoreSignals(&set);
- return ret;
-}
-
-fn blockAllSignals(set: *sigset_t) void {
- _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
-}
-
-fn blockAppSignals(set: *sigset_t) void {
- _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
-}
-
-fn restoreSignals(set: *sigset_t) void {
- _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
-}
-
-pub fn sigaddset(set: *sigset_t, sig: u6) void {
- const s = sig - 1;
- (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1));
-}
-
-pub fn sigismember(set: *const sigset_t, sig: u6) bool {
- const s = sig - 1;
- return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
-}
-
-pub const in_port_t = u16;
-pub const sa_family_t = u16;
-pub const socklen_t = u32;
-
-/// This intentionally only has ip4 and ip6
-pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
-};
-
-pub const sockaddr_in = extern struct {
- family: sa_family_t,
- port: in_port_t,
- addr: u32,
- zero: [8]u8,
-};
-
-pub const sockaddr_in6 = extern struct {
- family: sa_family_t,
- port: in_port_t,
- flowinfo: u32,
- addr: [16]u8,
- scope_id: u32,
-};
-
-pub const sockaddr_un = extern struct {
- family: sa_family_t,
- path: [108]u8,
-};
-
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
- return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
-}
-
-pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
- return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
-}
-
-pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
- return syscall3(SYS_socket, domain, socket_type, protocol);
-}
-
-pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
- return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
-}
-
-pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
- return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
-}
-
-pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
- return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
-}
-
-pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
- return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
-}
-
-pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
- return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
-}
-
-pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
- return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
-}
-
-pub fn shutdown(fd: i32, how: i32) usize {
- return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
-}
-
-pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
- return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
-}
-
-pub fn listen(fd: i32, backlog: u32) usize {
- return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
-}
-
-pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
- return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
-}
-
-pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
- return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
-}
-
-pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
- return accept4(fd, addr, len, 0);
-}
-
-pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
- return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
-}
-
-pub fn fstat(fd: i32, stat_buf: *Stat) usize {
- return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
- return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
- return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
- return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
- return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize {
- return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size);
-}
-
-pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize {
- return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
- return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize {
- return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize {
- return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
- return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
- return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize {
- return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags);
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn removexattr(path: [*]const u8, name: [*]const u8) usize {
- return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize {
- return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
- return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
-}
-
-pub fn sched_getaffinity(pid: i32, set: []usize) usize {
- return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
-}
-
-pub const epoll_data = packed union {
- ptr: usize,
- fd: i32,
- @"u32": u32,
- @"u64": u64,
-};
-
-pub const epoll_event = packed struct {
- events: u32,
- data: epoll_data,
-};
-
-pub fn epoll_create() usize {
- return epoll_create1(0);
-}
-
-pub fn epoll_create1(flags: usize) usize {
- return syscall1(SYS_epoll_create1, flags);
-}
-
-pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
- return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
-}
-
-pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
- return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
-}
-
-pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
- return syscall6(
- SYS_epoll_pwait,
- @bitCast(usize, isize(epoll_fd)),
- @ptrToInt(events),
- @intCast(usize, maxevents),
- @bitCast(usize, isize(timeout)),
- @ptrToInt(sigmask),
- @sizeOf(sigset_t),
- );
-}
-
-pub fn eventfd(count: u32, flags: u32) usize {
- return syscall2(SYS_eventfd2, count, flags);
-}
-
-pub fn timerfd_create(clockid: i32, flags: u32) usize {
- return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
-}
-
-pub const itimerspec = extern struct {
- it_interval: timespec,
- it_value: timespec,
-};
-
-pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
- return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
-}
-
-pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
- return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
-}
-
-pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
-pub const _LINUX_CAPABILITY_U32S_1 = 1;
-
-pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
-pub const _LINUX_CAPABILITY_U32S_2 = 2;
-
-pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
-pub const _LINUX_CAPABILITY_U32S_3 = 2;
-
-pub const VFS_CAP_REVISION_MASK = 0xFF000000;
-pub const VFS_CAP_REVISION_SHIFT = 24;
-pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
-pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
-
-pub const VFS_CAP_REVISION_1 = 0x01000000;
-pub const VFS_CAP_U32_1 = 1;
-pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
-
-pub const VFS_CAP_REVISION_2 = 0x02000000;
-pub const VFS_CAP_U32_2 = 2;
-pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
-
-pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
-pub const VFS_CAP_U32 = VFS_CAP_U32_2;
-pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
-
-pub const vfs_cap_data = extern struct {
- //all of these are mandated as little endian
- //when on disk.
- const Data = struct {
- permitted: u32,
- inheritable: u32,
- };
-
- magic_etc: u32,
- data: [VFS_CAP_U32]Data,
-};
-
-pub const CAP_CHOWN = 0;
-pub const CAP_DAC_OVERRIDE = 1;
-pub const CAP_DAC_READ_SEARCH = 2;
-pub const CAP_FOWNER = 3;
-pub const CAP_FSETID = 4;
-pub const CAP_KILL = 5;
-pub const CAP_SETGID = 6;
-pub const CAP_SETUID = 7;
-pub const CAP_SETPCAP = 8;
-pub const CAP_LINUX_IMMUTABLE = 9;
-pub const CAP_NET_BIND_SERVICE = 10;
-pub const CAP_NET_BROADCAST = 11;
-pub const CAP_NET_ADMIN = 12;
-pub const CAP_NET_RAW = 13;
-pub const CAP_IPC_LOCK = 14;
-pub const CAP_IPC_OWNER = 15;
-pub const CAP_SYS_MODULE = 16;
-pub const CAP_SYS_RAWIO = 17;
-pub const CAP_SYS_CHROOT = 18;
-pub const CAP_SYS_PTRACE = 19;
-pub const CAP_SYS_PACCT = 20;
-pub const CAP_SYS_ADMIN = 21;
-pub const CAP_SYS_BOOT = 22;
-pub const CAP_SYS_NICE = 23;
-pub const CAP_SYS_RESOURCE = 24;
-pub const CAP_SYS_TIME = 25;
-pub const CAP_SYS_TTY_CONFIG = 26;
-pub const CAP_MKNOD = 27;
-pub const CAP_LEASE = 28;
-pub const CAP_AUDIT_WRITE = 29;
-pub const CAP_AUDIT_CONTROL = 30;
-pub const CAP_SETFCAP = 31;
-pub const CAP_MAC_OVERRIDE = 32;
-pub const CAP_MAC_ADMIN = 33;
-pub const CAP_SYSLOG = 34;
-pub const CAP_WAKE_ALARM = 35;
-pub const CAP_BLOCK_SUSPEND = 36;
-pub const CAP_AUDIT_READ = 37;
-pub const CAP_LAST_CAP = CAP_AUDIT_READ;
-
-pub fn cap_valid(u8: x) bool {
- return x >= 0 and x <= CAP_LAST_CAP;
-}
-
-pub fn CAP_TO_MASK(cap: u8) u32 {
- return u32(1) << u5(cap & 31);
-}
-
-pub fn CAP_TO_INDEX(cap: u8) u8 {
- return cap >> 5;
-}
-
-pub const cap_t = extern struct {
- hdrp: *cap_user_header_t,
- datap: *cap_user_data_t,
-};
-
-pub const cap_user_header_t = extern struct {
- version: u32,
- pid: usize,
-};
-
-pub const cap_user_data_t = extern struct {
- effective: u32,
- permitted: u32,
- inheritable: u32,
-};
-
-pub fn unshare(flags: usize) usize {
- return syscall1(SYS_unshare, flags);
-}
-
-pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize {
- return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap));
-}
-
-pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
- return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
-}
-
-pub const inotify_event = extern struct {
- wd: i32,
- mask: u32,
- cookie: u32,
- len: u32,
- //name: [?]u8,
-};
-
-pub const dirent64 = extern struct {
- d_ino: u64,
- d_off: u64,
- d_reclen: u16,
- d_type: u8,
- d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
-};
-
-test "import" {
- if (builtin.os == builtin.Os.linux) {
- _ = @import("test.zig");
- }
-}
diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig
index 40fb7823d2c9f00ff29f83c7738464579a91f152..286748b70c3b98fb21c52f1748dbf53b40ce5e52 100644
--- a/std/os/linux/test.zig
+++ b/std/os/linux/test.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const builtin = @import("builtin");
const linux = std.os.linux;
const expect = std.testing.expect;
diff --git a/std/os/linux/vdso.zig b/std/os/linux/vdso.zig
index 07745ad1ebc2c42cef872a3b00ef9b4533a75938..efd69d8542478809e8a4a456fe48f9e1cd6e06f2 100644
--- a/std/os/linux/vdso.zig
+++ b/std/os/linux/vdso.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const elf = std.elf;
const linux = std.os.linux;
const cstr = std.cstr;
diff --git a/std/os/linux/x86_64.zig b/std/os/linux/x86_64.zig
index 2ea369d9f289554ad94918dd30f0434b45e8d0d8..d194cd4003cf760c49bb67784448d8782634e54f 100644
--- a/std/os/linux/x86_64.zig
+++ b/std/os/linux/x86_64.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
const iovec = linux.iovec;
diff --git a/std/os/netbsd.zig b/std/os/netbsd.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2d4b6ff1246d26b811d65a67a400addb430626a8
--- /dev/null
+++ b/std/os/netbsd.zig
@@ -0,0 +1,724 @@
+const builtin = @import("builtin");
+
+pub use @import("netbsd/errno.zig");
+
+const std = @import("../std.zig");
+const c = std.c;
+
+const assert = std.debug.assert;
+const maxInt = std.math.maxInt;
+pub const Kevent = c.Kevent;
+
+pub const CTL_KERN = 1;
+pub const CTL_DEBUG = 5;
+
+pub const KERN_PROC_ARGS = 48; // struct: process argv/env
+pub const KERN_PROC_PATHNAME = 5; // path to executable
+
+pub const PATH_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_VIRTUAL = 1;
+pub const CLOCK_PROF = 2;
+pub const CLOCK_MONOTONIC = 3;
+pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
+pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
+
+pub const MAP_FAILED = maxInt(usize);
+pub const MAP_SHARED = 0x0001;
+pub const MAP_PRIVATE = 0x0002;
+pub const MAP_REMAPDUP = 0x0004;
+pub const MAP_FIXED = 0x0010;
+pub const MAP_RENAME = 0x0020;
+pub const MAP_NORESERVE = 0x0040;
+pub const MAP_INHERIT = 0x0080;
+pub const MAP_HASSEMAPHORE = 0x0200;
+pub const MAP_TRYFIXED = 0x0400;
+pub const MAP_WIRED = 0x0800;
+
+pub const MAP_FILE = 0x0000;
+pub const MAP_NOSYNC = 0x0800;
+pub const MAP_ANON = 0x1000;
+pub const MAP_ANONYMOUS = MAP_ANON;
+pub const MAP_STACK = 0x2000;
+
+pub const WNOHANG = 0x00000001;
+pub const WUNTRACED = 0x00000002;
+pub const WSTOPPED = WUNTRACED;
+pub const WCONTINUED = 0x00000010;
+pub const WNOWAIT = 0x00010000;
+pub const WEXITED = 0x00000020;
+pub const WTRAPPED = 0x00000040;
+
+pub const SA_ONSTACK = 0x0001;
+pub const SA_RESTART = 0x0002;
+pub const SA_RESETHAND = 0x0004;
+pub const SA_NOCLDSTOP = 0x0008;
+pub const SA_NODEFER = 0x0010;
+pub const SA_NOCLDWAIT = 0x0020;
+pub const SA_SIGINFO = 0x0040;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGEMT = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGBUS = 10;
+pub const SIGSEGV = 11;
+pub const SIGSYS = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGURG = 16;
+pub const SIGSTOP = 17;
+pub const SIGTSTP = 18;
+pub const SIGCONT = 19;
+pub const SIGCHLD = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGIO = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGINFO = 29;
+pub const SIGUSR1 = 30;
+pub const SIGUSR2 = 31;
+pub const SIGPWR = 32;
+
+pub const SIGRTMIN = 33;
+pub const SIGRTMAX = 63;
+
+// access function
+pub const F_OK = 0; // test for existence of file
+pub const X_OK = 1; // test for execute or search permission
+pub const W_OK = 2; // test for write permission
+pub const R_OK = 4; // test for read permission
+
+pub const O_RDONLY = 0x0000;
+pub const O_WRONLY = 0x0001;
+pub const O_RDWR = 0x0002;
+pub const O_ACCMODE = 0x0003;
+
+pub const O_CREAT = 0x0200;
+pub const O_EXCL = 0x0800;
+pub const O_NOCTTY = 0x8000;
+pub const O_TRUNC = 0x0400;
+pub const O_APPEND = 0x0008;
+pub const O_NONBLOCK = 0x0004;
+pub const O_DSYNC = 0x00010000;
+pub const O_SYNC = 0x0080;
+pub const O_RSYNC = 0x00020000;
+pub const O_DIRECTORY = 0x00080000;
+pub const O_NOFOLLOW = 0x00000100;
+pub const O_CLOEXEC = 0x00400000;
+
+pub const O_ASYNC = 0x0040;
+pub const O_DIRECT = 0x00080000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0;
+pub const O_PATH = 0;
+pub const O_TMPFILE = 0;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_GETOWN = 5;
+pub const F_SETOWN = 6;
+
+pub const F_GETLK = 7;
+pub const F_SETLK = 8;
+pub const F_SETLKW = 9;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 1;
+pub const SIG_UNBLOCK = 2;
+pub const SIG_SETMASK = 3;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+
+pub const SOCK_CLOEXEC = 0x10000000;
+pub const SOCK_NONBLOCK = 0x20000000;
+
+pub const PROTO_ip = 0;
+pub const PROTO_icmp = 1;
+pub const PROTO_igmp = 2;
+pub const PROTO_ggp = 3;
+pub const PROTO_ipencap = 4;
+pub const PROTO_tcp = 6;
+pub const PROTO_egp = 8;
+pub const PROTO_pup = 12;
+pub const PROTO_udp = 17;
+pub const PROTO_xns_idp = 22;
+pub const PROTO_iso_tp4 = 29;
+pub const PROTO_ipv6 = 41;
+pub const PROTO_ipv6_route = 43;
+pub const PROTO_ipv6_frag = 44;
+pub const PROTO_rsvp = 46;
+pub const PROTO_gre = 47;
+pub const PROTO_esp = 50;
+pub const PROTO_ah = 51;
+pub const PROTO_ipv6_icmp = 58;
+pub const PROTO_ipv6_nonxt = 59;
+pub const PROTO_ipv6_opts = 60;
+pub const PROTO_encap = 98;
+pub const PROTO_pim = 103;
+pub const PROTO_raw = 255;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_APPLETALK = 16;
+pub const PF_INET6 = 24;
+pub const PF_DECnet = 12;
+pub const PF_KEY = 29;
+pub const PF_ROUTE = 34;
+pub const PF_SNA = 11;
+pub const PF_MPLS = 33;
+pub const PF_CAN = 35;
+pub const PF_BLUETOOTH = 31;
+pub const PF_ISDN = 26;
+pub const PF_MAX = 37;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_INET6 = PF_INET6;
+pub const AF_KEY = PF_KEY;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_SNA = PF_SNA;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_MAX = PF_MAX;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
+
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
+
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+pub const EVFILT_READ = 0;
+pub const EVFILT_WRITE = 1;
+
+/// attached to aio requests
+pub const EVFILT_AIO = 2;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = 3;
+
+/// attached to struct proc
+pub const EVFILT_PROC = 4;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = 5;
+
+/// timers
+pub const EVFILT_TIMER = 6;
+
+/// Filesystem events
+pub const EVFILT_FS = 7;
+
+/// On input, NOTE_TRIGGER causes the event to be triggered for output.
+pub const NOTE_TRIGGER = 0x08000000;
+
+/// low water mark
+pub const NOTE_LOWAT = 0x00000001;
+
+/// vnode was removed
+pub const NOTE_DELETE = 0x00000001;
+
+/// data contents changed
+pub const NOTE_WRITE = 0x00000002;
+
+/// size increased
+pub const NOTE_EXTEND = 0x00000004;
+
+/// attributes changed
+pub const NOTE_ATTRIB = 0x00000008;
+
+/// link count changed
+pub const NOTE_LINK = 0x00000010;
+
+/// vnode was renamed
+pub const NOTE_RENAME = 0x00000020;
+
+/// vnode access was revoked
+pub const NOTE_REVOKE = 0x00000040;
+
+/// process exited
+pub const NOTE_EXIT = 0x80000000;
+
+/// process forked
+pub const NOTE_FORK = 0x40000000;
+
+/// process exec'd
+pub const NOTE_EXEC = 0x20000000;
+
+/// mask for signal & exit status
+pub const NOTE_PDATAMASK = 0x000fffff;
+pub const NOTE_PCTRLMASK = 0xf0000000;
+
+pub const TIOCCBRK = 0x2000747a;
+pub const TIOCCDTR = 0x20007478;
+pub const TIOCCONS = 0x80047462;
+pub const TIOCDCDTIMESTAMP = 0x40107458;
+pub const TIOCDRAIN = 0x2000745e;
+pub const TIOCEXCL = 0x2000740d;
+pub const TIOCEXT = 0x80047460;
+pub const TIOCFLAG_CDTRCTS = 0x10;
+pub const TIOCFLAG_CLOCAL = 0x2;
+pub const TIOCFLAG_CRTSCTS = 0x4;
+pub const TIOCFLAG_MDMBUF = 0x8;
+pub const TIOCFLAG_SOFTCAR = 0x1;
+pub const TIOCFLUSH = 0x80047410;
+pub const TIOCGETA = 0x402c7413;
+pub const TIOCGETD = 0x4004741a;
+pub const TIOCGFLAGS = 0x4004745d;
+pub const TIOCGLINED = 0x40207442;
+pub const TIOCGPGRP = 0x40047477;
+pub const TIOCGQSIZE = 0x40047481;
+pub const TIOCGRANTPT = 0x20007447;
+pub const TIOCGSID = 0x40047463;
+pub const TIOCGSIZE = 0x40087468;
+pub const TIOCGWINSZ = 0x40087468;
+pub const TIOCMBIC = 0x8004746b;
+pub const TIOCMBIS = 0x8004746c;
+pub const TIOCMGET = 0x4004746a;
+pub const TIOCMSET = 0x8004746d;
+pub const TIOCM_CAR = 0x40;
+pub const TIOCM_CD = 0x40;
+pub const TIOCM_CTS = 0x20;
+pub const TIOCM_DSR = 0x100;
+pub const TIOCM_DTR = 0x2;
+pub const TIOCM_LE = 0x1;
+pub const TIOCM_RI = 0x80;
+pub const TIOCM_RNG = 0x80;
+pub const TIOCM_RTS = 0x4;
+pub const TIOCM_SR = 0x10;
+pub const TIOCM_ST = 0x8;
+pub const TIOCNOTTY = 0x20007471;
+pub const TIOCNXCL = 0x2000740e;
+pub const TIOCOUTQ = 0x40047473;
+pub const TIOCPKT = 0x80047470;
+pub const TIOCPKT_DATA = 0x0;
+pub const TIOCPKT_DOSTOP = 0x20;
+pub const TIOCPKT_FLUSHREAD = 0x1;
+pub const TIOCPKT_FLUSHWRITE = 0x2;
+pub const TIOCPKT_IOCTL = 0x40;
+pub const TIOCPKT_NOSTOP = 0x10;
+pub const TIOCPKT_START = 0x8;
+pub const TIOCPKT_STOP = 0x4;
+pub const TIOCPTMGET = 0x40287446;
+pub const TIOCPTSNAME = 0x40287448;
+pub const TIOCRCVFRAME = 0x80087445;
+pub const TIOCREMOTE = 0x80047469;
+pub const TIOCSBRK = 0x2000747b;
+pub const TIOCSCTTY = 0x20007461;
+pub const TIOCSDTR = 0x20007479;
+pub const TIOCSETA = 0x802c7414;
+pub const TIOCSETAF = 0x802c7416;
+pub const TIOCSETAW = 0x802c7415;
+pub const TIOCSETD = 0x8004741b;
+pub const TIOCSFLAGS = 0x8004745c;
+pub const TIOCSIG = 0x2000745f;
+pub const TIOCSLINED = 0x80207443;
+pub const TIOCSPGRP = 0x80047476;
+pub const TIOCSQSIZE = 0x80047480;
+pub const TIOCSSIZE = 0x80087467;
+pub const TIOCSTART = 0x2000746e;
+pub const TIOCSTAT = 0x80047465;
+pub const TIOCSTI = 0x80017472;
+pub const TIOCSTOP = 0x2000746f;
+pub const TIOCSWINSZ = 0x80087467;
+pub const TIOCUCNTL = 0x80047466;
+pub const TIOCXMTFRAME = 0x80087444;
+
+pub const sockaddr = c.sockaddr;
+pub const sockaddr_in = c.sockaddr_in;
+pub const sockaddr_in6 = c.sockaddr_in6;
+
+fn unsigned(s: i32) u32 {
+ return @bitCast(u32, s);
+}
+fn signed(s: u32) i32 {
+ return @bitCast(i32, s);
+}
+pub fn WEXITSTATUS(s: i32) i32 {
+ return signed((unsigned(s) >> 8) & 0xff);
+}
+pub fn WTERMSIG(s: i32) i32 {
+ return signed(unsigned(s) & 0x7f);
+}
+pub fn WSTOPSIG(s: i32) i32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: i32) bool {
+ return WTERMSIG(s) == 0;
+}
+
+pub fn WIFCONTINUED(s: i32) bool {
+ return ((s & 0x7f) == 0xffff);
+}
+
+pub fn WIFSTOPPED(s: i32) bool {
+ return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
+}
+
+pub fn WIFSIGNALED(s: i32) bool {
+ return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+/// Get the errno from a syscall return value, or 0 for no error.
+pub fn getErrno(r: usize) usize {
+ const signed_r = @bitCast(isize, r);
+ return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+}
+
+pub fn dup2(old: i32, new: i32) usize {
+ return errnoWrap(c.dup2(old, new));
+}
+
+pub fn chdir(path: [*]const u8) usize {
+ return errnoWrap(c.chdir(path));
+}
+
+pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
+ return errnoWrap(c.execve(path, argv, envp));
+}
+
+pub fn fork() usize {
+ return errnoWrap(c.fork());
+}
+
+pub fn access(path: [*]const u8, mode: u32) usize {
+ return errnoWrap(c.access(path, mode));
+}
+
+pub fn getcwd(buf: [*]u8, size: usize) usize {
+ return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
+}
+
+pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
+ return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
+}
+
+pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
+ return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
+}
+
+pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
+ return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
+}
+
+pub fn isatty(fd: i32) bool {
+ return c.isatty(fd) != 0;
+}
+
+pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
+ return errnoWrap(c.readlink(path, buf_ptr, buf_len));
+}
+
+pub fn mkdir(path: [*]const u8, mode: u32) usize {
+ return errnoWrap(c.mkdir(path, mode));
+}
+
+pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
+ const ptr_result = c.mmap(
+ @ptrCast(?*c_void, address),
+ length,
+ @bitCast(c_int, @intCast(c_uint, prot)),
+ @bitCast(c_int, c_uint(flags)),
+ fd,
+ offset,
+ );
+ const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
+ return errnoWrap(isize_result);
+}
+
+pub fn munmap(address: usize, length: usize) usize {
+ return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
+}
+
+pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
+ return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
+}
+
+pub fn rmdir(path: [*]const u8) usize {
+ return errnoWrap(c.rmdir(path));
+}
+
+pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
+ return errnoWrap(c.symlink(existing, new));
+}
+
+pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
+ return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
+}
+
+pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
+ return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
+}
+
+pub fn pipe(fd: *[2]i32) usize {
+ return pipe2(fd, 0);
+}
+
+pub fn pipe2(fd: *[2]i32, flags: u32) usize {
+ comptime assert(i32.bit_count == c_int.bit_count);
+ return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
+}
+
+pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
+ return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
+}
+
+pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
+ return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
+}
+
+pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
+ return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
+}
+
+pub fn rename(old: [*]const u8, new: [*]const u8) usize {
+ return errnoWrap(c.rename(old, new));
+}
+
+pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
+ return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
+}
+
+pub fn create(path: [*]const u8, perm: usize) usize {
+ return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
+}
+
+pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
+ return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
+}
+
+pub fn close(fd: i32) usize {
+ return errnoWrap(c.close(fd));
+}
+
+pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
+ return errnoWrap(c.lseek(fd, offset, whence));
+}
+
+pub fn exit(code: i32) noreturn {
+ c.exit(code);
+}
+
+pub fn kill(pid: i32, sig: i32) usize {
+ return errnoWrap(c.kill(pid, sig));
+}
+
+pub fn unlink(path: [*]const u8) usize {
+ return errnoWrap(c.unlink(path));
+}
+
+pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
+ comptime assert(i32.bit_count == c_int.bit_count);
+ return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
+}
+
+pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
+ return errnoWrap(c.nanosleep(req, rem));
+}
+
+pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
+ return errnoWrap(c.clock_gettime(clk_id, tp));
+}
+
+pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
+ return errnoWrap(c.clock_getres(clk_id, tp));
+}
+
+pub fn setuid(uid: u32) usize {
+ return errnoWrap(c.setuid(uid));
+}
+
+pub fn setgid(gid: u32) usize {
+ return errnoWrap(c.setgid(gid));
+}
+
+pub fn setreuid(ruid: u32, euid: u32) usize {
+ return errnoWrap(c.setreuid(ruid, euid));
+}
+
+pub fn setregid(rgid: u32, egid: u32) usize {
+ return errnoWrap(c.setregid(rgid, egid));
+}
+
+const NSIG = 32;
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = extern struct {
+ /// signal handler
+ __sigaction_u: extern union {
+ __sa_handler: extern fn (i32) void,
+ __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
+ },
+
+ /// see signal options
+ sa_flags: u32,
+
+ /// signal mask to apply
+ sa_mask: sigset_t,
+};
+
+pub const _SIG_WORDS = 4;
+pub const _SIG_MAXSIG = 128;
+
+pub inline fn _SIG_IDX(sig: usize) usize {
+ return sig - 1;
+}
+pub inline fn _SIG_WORD(sig: usize) usize {
+ return_SIG_IDX(sig) >> 5;
+}
+pub inline fn _SIG_BIT(sig: usize) usize {
+ return 1 << (_SIG_IDX(sig) & 31);
+}
+pub inline fn _SIG_VALID(sig: usize) usize {
+ return sig <= _SIG_MAXSIG and sig > 0;
+}
+
+pub const sigset_t = extern struct {
+ __bits: [_SIG_WORDS]u32,
+};
+
+pub fn raise(sig: i32) usize {
+ return errnoWrap(c.raise(sig));
+}
+
+pub const Stat = c.Stat;
+pub const dirent = c.dirent;
+pub const timespec = c.timespec;
+
+pub fn fstat(fd: i32, buf: *c.Stat) usize {
+ return errnoWrap(c.fstat(fd, buf));
+}
+pub const iovec = extern struct {
+ iov_base: [*]u8,
+ iov_len: usize,
+};
+
+pub const iovec_const = extern struct {
+ iov_base: [*]const u8,
+ iov_len: usize,
+};
+
+// TODO avoid libc dependency
+pub fn kqueue() usize {
+ return errnoWrap(c.kqueue());
+}
+
+// TODO avoid libc dependency
+pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
+ return errnoWrap(c.kevent(
+ kq,
+ changelist.ptr,
+ @intCast(c_int, changelist.len),
+ eventlist.ptr,
+ @intCast(c_int, eventlist.len),
+ timeout,
+ ));
+}
+
+// TODO avoid libc dependency
+pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
+ return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+}
+
+// TODO avoid libc dependency
+pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
+ return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
+}
+
+// TODO avoid libc dependency
+pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
+ return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
+}
+
+// TODO avoid libc dependency
+
+/// Takes the return value from a syscall and formats it back in the way
+/// that the kernel represents it to libc. Errno was a mistake, let's make
+/// it go away forever.
+fn errnoWrap(value: isize) usize {
+ return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
+}
diff --git a/std/os/netbsd/index.zig b/std/os/netbsd/index.zig
deleted file mode 100644
index ebabc3c801eaa340d67471dc914e890928205800..0000000000000000000000000000000000000000
--- a/std/os/netbsd/index.zig
+++ /dev/null
@@ -1,725 +0,0 @@
-const builtin = @import("builtin");
-
-pub use @import("errno.zig");
-
-const std = @import("../../index.zig");
-const c = std.c;
-
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-pub const Kevent = c.Kevent;
-
-pub const CTL_KERN = 1;
-pub const CTL_DEBUG = 5;
-
-pub const KERN_PROC_ARGS = 48; // struct: process argv/env
-pub const KERN_PROC_PATHNAME = 5; // path to executable
-
-pub const PATH_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_VIRTUAL = 1;
-pub const CLOCK_PROF = 2;
-pub const CLOCK_MONOTONIC = 3;
-pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
-pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x0001;
-pub const MAP_PRIVATE = 0x0002;
-pub const MAP_REMAPDUP = 0x0004;
-pub const MAP_FIXED = 0x0010;
-pub const MAP_RENAME = 0x0020;
-pub const MAP_NORESERVE = 0x0040;
-pub const MAP_INHERIT = 0x0080;
-pub const MAP_HASSEMAPHORE = 0x0200;
-pub const MAP_TRYFIXED = 0x0400;
-pub const MAP_WIRED = 0x0800;
-
-pub const MAP_FILE = 0x0000;
-pub const MAP_NOSYNC = 0x0800;
-pub const MAP_ANON = 0x1000;
-pub const MAP_ANONYMOUS = MAP_ANON;
-pub const MAP_STACK = 0x2000;
-
-pub const WNOHANG = 0x00000001;
-pub const WUNTRACED = 0x00000002;
-pub const WSTOPPED = WUNTRACED;
-pub const WCONTINUED = 0x00000010;
-pub const WNOWAIT = 0x00010000;
-pub const WEXITED = 0x00000020;
-pub const WTRAPPED = 0x00000040;
-
-pub const SA_ONSTACK = 0x0001;
-pub const SA_RESTART = 0x0002;
-pub const SA_RESETHAND = 0x0004;
-pub const SA_NOCLDSTOP = 0x0008;
-pub const SA_NODEFER = 0x0010;
-pub const SA_NOCLDWAIT = 0x0020;
-pub const SA_SIGINFO = 0x0040;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGEMT = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGBUS = 10;
-pub const SIGSEGV = 11;
-pub const SIGSYS = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGURG = 16;
-pub const SIGSTOP = 17;
-pub const SIGTSTP = 18;
-pub const SIGCONT = 19;
-pub const SIGCHLD = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGIO = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGINFO = 29;
-pub const SIGUSR1 = 30;
-pub const SIGUSR2 = 31;
-pub const SIGPWR = 32;
-
-pub const SIGRTMIN = 33;
-pub const SIGRTMAX = 63;
-
-// access function
-pub const F_OK = 0; // test for existence of file
-pub const X_OK = 1; // test for execute or search permission
-pub const W_OK = 2; // test for write permission
-pub const R_OK = 4; // test for read permission
-
-
-pub const O_RDONLY = 0x0000;
-pub const O_WRONLY = 0x0001;
-pub const O_RDWR = 0x0002;
-pub const O_ACCMODE = 0x0003;
-
-pub const O_CREAT = 0x0200;
-pub const O_EXCL = 0x0800;
-pub const O_NOCTTY = 0x8000;
-pub const O_TRUNC = 0x0400;
-pub const O_APPEND = 0x0008;
-pub const O_NONBLOCK = 0x0004;
-pub const O_DSYNC = 0x00010000;
-pub const O_SYNC = 0x0080;
-pub const O_RSYNC = 0x00020000;
-pub const O_DIRECTORY = 0x00080000;
-pub const O_NOFOLLOW = 0x00000100;
-pub const O_CLOEXEC = 0x00400000;
-
-pub const O_ASYNC = 0x0040;
-pub const O_DIRECT = 0x00080000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0;
-pub const O_PATH = 0;
-pub const O_TMPFILE = 0;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_GETOWN = 5;
-pub const F_SETOWN = 6;
-
-pub const F_GETLK = 7;
-pub const F_SETLK = 8;
-pub const F_SETLKW = 9;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 1;
-pub const SIG_UNBLOCK = 2;
-pub const SIG_SETMASK = 3;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-
-pub const SOCK_CLOEXEC = 0x10000000;
-pub const SOCK_NONBLOCK = 0x20000000;
-
-pub const PROTO_ip = 0;
-pub const PROTO_icmp = 1;
-pub const PROTO_igmp = 2;
-pub const PROTO_ggp = 3;
-pub const PROTO_ipencap = 4;
-pub const PROTO_tcp = 6;
-pub const PROTO_egp = 8;
-pub const PROTO_pup = 12;
-pub const PROTO_udp = 17;
-pub const PROTO_xns_idp = 22;
-pub const PROTO_iso_tp4 = 29;
-pub const PROTO_ipv6 = 41;
-pub const PROTO_ipv6_route = 43;
-pub const PROTO_ipv6_frag = 44;
-pub const PROTO_rsvp = 46;
-pub const PROTO_gre = 47;
-pub const PROTO_esp = 50;
-pub const PROTO_ah = 51;
-pub const PROTO_ipv6_icmp = 58;
-pub const PROTO_ipv6_nonxt = 59;
-pub const PROTO_ipv6_opts = 60;
-pub const PROTO_encap = 98;
-pub const PROTO_pim = 103;
-pub const PROTO_raw = 255;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_APPLETALK = 16;
-pub const PF_INET6 = 24;
-pub const PF_DECnet = 12;
-pub const PF_KEY = 29;
-pub const PF_ROUTE = 34;
-pub const PF_SNA = 11;
-pub const PF_MPLS = 33;
-pub const PF_CAN = 35;
-pub const PF_BLUETOOTH = 31;
-pub const PF_ISDN = 26;
-pub const PF_MAX = 37;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_INET6 = PF_INET6;
-pub const AF_KEY = PF_KEY;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_SNA = PF_SNA;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_MAX = PF_MAX;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-pub const EVFILT_READ = 0;
-pub const EVFILT_WRITE = 1;
-
-/// attached to aio requests
-pub const EVFILT_AIO = 2;
-
-/// attached to vnodes
-pub const EVFILT_VNODE = 3;
-
-/// attached to struct proc
-pub const EVFILT_PROC = 4;
-
-/// attached to struct proc
-pub const EVFILT_SIGNAL = 5;
-
-/// timers
-pub const EVFILT_TIMER = 6;
-
-/// Filesystem events
-pub const EVFILT_FS = 7;
-
-/// On input, NOTE_TRIGGER causes the event to be triggered for output.
-pub const NOTE_TRIGGER = 0x08000000;
-
-/// low water mark
-pub const NOTE_LOWAT = 0x00000001;
-
-/// vnode was removed
-pub const NOTE_DELETE = 0x00000001;
-
-/// data contents changed
-pub const NOTE_WRITE = 0x00000002;
-
-/// size increased
-pub const NOTE_EXTEND = 0x00000004;
-
-/// attributes changed
-pub const NOTE_ATTRIB = 0x00000008;
-
-/// link count changed
-pub const NOTE_LINK = 0x00000010;
-
-/// vnode was renamed
-pub const NOTE_RENAME = 0x00000020;
-
-/// vnode access was revoked
-pub const NOTE_REVOKE = 0x00000040;
-
-/// process exited
-pub const NOTE_EXIT = 0x80000000;
-
-/// process forked
-pub const NOTE_FORK = 0x40000000;
-
-/// process exec'd
-pub const NOTE_EXEC = 0x20000000;
-
-/// mask for signal & exit status
-pub const NOTE_PDATAMASK = 0x000fffff;
-pub const NOTE_PCTRLMASK = 0xf0000000;
-
-pub const TIOCCBRK = 0x2000747a;
-pub const TIOCCDTR = 0x20007478;
-pub const TIOCCONS = 0x80047462;
-pub const TIOCDCDTIMESTAMP = 0x40107458;
-pub const TIOCDRAIN = 0x2000745e;
-pub const TIOCEXCL = 0x2000740d;
-pub const TIOCEXT = 0x80047460;
-pub const TIOCFLAG_CDTRCTS = 0x10;
-pub const TIOCFLAG_CLOCAL = 0x2;
-pub const TIOCFLAG_CRTSCTS = 0x4;
-pub const TIOCFLAG_MDMBUF = 0x8;
-pub const TIOCFLAG_SOFTCAR = 0x1;
-pub const TIOCFLUSH = 0x80047410;
-pub const TIOCGETA = 0x402c7413;
-pub const TIOCGETD = 0x4004741a;
-pub const TIOCGFLAGS = 0x4004745d;
-pub const TIOCGLINED = 0x40207442;
-pub const TIOCGPGRP = 0x40047477;
-pub const TIOCGQSIZE = 0x40047481;
-pub const TIOCGRANTPT = 0x20007447;
-pub const TIOCGSID = 0x40047463;
-pub const TIOCGSIZE = 0x40087468;
-pub const TIOCGWINSZ = 0x40087468;
-pub const TIOCMBIC = 0x8004746b;
-pub const TIOCMBIS = 0x8004746c;
-pub const TIOCMGET = 0x4004746a;
-pub const TIOCMSET = 0x8004746d;
-pub const TIOCM_CAR = 0x40;
-pub const TIOCM_CD = 0x40;
-pub const TIOCM_CTS = 0x20;
-pub const TIOCM_DSR = 0x100;
-pub const TIOCM_DTR = 0x2;
-pub const TIOCM_LE = 0x1;
-pub const TIOCM_RI = 0x80;
-pub const TIOCM_RNG = 0x80;
-pub const TIOCM_RTS = 0x4;
-pub const TIOCM_SR = 0x10;
-pub const TIOCM_ST = 0x8;
-pub const TIOCNOTTY = 0x20007471;
-pub const TIOCNXCL = 0x2000740e;
-pub const TIOCOUTQ = 0x40047473;
-pub const TIOCPKT = 0x80047470;
-pub const TIOCPKT_DATA = 0x0;
-pub const TIOCPKT_DOSTOP = 0x20;
-pub const TIOCPKT_FLUSHREAD = 0x1;
-pub const TIOCPKT_FLUSHWRITE = 0x2;
-pub const TIOCPKT_IOCTL = 0x40;
-pub const TIOCPKT_NOSTOP = 0x10;
-pub const TIOCPKT_START = 0x8;
-pub const TIOCPKT_STOP = 0x4;
-pub const TIOCPTMGET = 0x40287446;
-pub const TIOCPTSNAME = 0x40287448;
-pub const TIOCRCVFRAME = 0x80087445;
-pub const TIOCREMOTE = 0x80047469;
-pub const TIOCSBRK = 0x2000747b;
-pub const TIOCSCTTY = 0x20007461;
-pub const TIOCSDTR = 0x20007479;
-pub const TIOCSETA = 0x802c7414;
-pub const TIOCSETAF = 0x802c7416;
-pub const TIOCSETAW = 0x802c7415;
-pub const TIOCSETD = 0x8004741b;
-pub const TIOCSFLAGS = 0x8004745c;
-pub const TIOCSIG = 0x2000745f;
-pub const TIOCSLINED = 0x80207443;
-pub const TIOCSPGRP = 0x80047476;
-pub const TIOCSQSIZE = 0x80047480;
-pub const TIOCSSIZE = 0x80087467;
-pub const TIOCSTART = 0x2000746e;
-pub const TIOCSTAT = 0x80047465;
-pub const TIOCSTI = 0x80017472;
-pub const TIOCSTOP = 0x2000746f;
-pub const TIOCSWINSZ = 0x80087467;
-pub const TIOCUCNTL = 0x80047466;
-pub const TIOCXMTFRAME = 0x80087444;
-
-pub const sockaddr = c.sockaddr;
-pub const sockaddr_in = c.sockaddr_in;
-pub const sockaddr_in6 = c.sockaddr_in6;
-
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) >> 8) & 0xff);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-
-pub fn WIFCONTINUED(s: i32) bool {
- return ((s & 0x7f) == 0xffff);
-}
-
-pub fn WIFSTOPPED(s: i32) bool {
- return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
-}
-
-pub fn WIFSIGNALED(s: i32) bool {
- return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
-}
-
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return errnoWrap(c.dup2(old, new));
-}
-
-pub fn chdir(path: [*]const u8) usize {
- return errnoWrap(c.chdir(path));
-}
-
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return errnoWrap(c.execve(path, argv, envp));
-}
-
-pub fn fork() usize {
- return errnoWrap(c.fork());
-}
-
-pub fn access(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.access(path, mode));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
- return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
-}
-
-pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
- return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
-}
-
-pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
- return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn isatty(fd: i32) bool {
- return c.isatty(fd) != 0;
-}
-
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return errnoWrap(c.readlink(path, buf_ptr, buf_len));
-}
-
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.mkdir(path, mode));
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- const ptr_result = c.mmap(
- @ptrCast(?*c_void, address),
- length,
- @bitCast(c_int, @intCast(c_uint, prot)),
- @bitCast(c_int, c_uint(flags)),
- fd,
- offset,
- );
- const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
- return errnoWrap(isize_result);
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
-}
-
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
-}
-
-pub fn rmdir(path: [*]const u8) usize {
- return errnoWrap(c.rmdir(path));
-}
-
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.symlink(existing, new));
-}
-
-pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
-}
-
-pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
- return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
-}
-
-pub fn pipe2(fd: *[2]i32, flags: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
-}
-
-pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
- return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
-}
-
-pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
- return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.rename(old, new));
-}
-
-pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
- return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
-}
-
-pub fn create(path: [*]const u8, perm: usize) usize {
- return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
-}
-
-pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
- return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
-}
-
-pub fn close(fd: i32) usize {
- return errnoWrap(c.close(fd));
-}
-
-pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
- return errnoWrap(c.lseek(fd, offset, whence));
-}
-
-pub fn exit(code: i32) noreturn {
- c.exit(code);
-}
-
-pub fn kill(pid: i32, sig: i32) usize {
- return errnoWrap(c.kill(pid, sig));
-}
-
-pub fn unlink(path: [*]const u8) usize {
- return errnoWrap(c.unlink(path));
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return errnoWrap(c.nanosleep(req, rem));
-}
-
-pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_gettime(clk_id, tp));
-}
-
-pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_getres(clk_id, tp));
-}
-
-pub fn setuid(uid: u32) usize {
- return errnoWrap(c.setuid(uid));
-}
-
-pub fn setgid(gid: u32) usize {
- return errnoWrap(c.setgid(gid));
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return errnoWrap(c.setreuid(ruid, euid));
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return errnoWrap(c.setregid(rgid, egid));
-}
-
-const NSIG = 32;
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = extern struct {
- /// signal handler
- __sigaction_u: extern union {
- __sa_handler: extern fn (i32) void,
- __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
- },
-
- /// see signal options
- sa_flags: u32,
-
- /// signal mask to apply
- sa_mask: sigset_t,
-};
-
-pub const _SIG_WORDS = 4;
-pub const _SIG_MAXSIG = 128;
-
-pub inline fn _SIG_IDX(sig: usize) usize {
- return sig - 1;
-}
-pub inline fn _SIG_WORD(sig: usize) usize {
- return_SIG_IDX(sig) >> 5;
-}
-pub inline fn _SIG_BIT(sig: usize) usize {
- return 1 << (_SIG_IDX(sig) & 31);
-}
-pub inline fn _SIG_VALID(sig: usize) usize {
- return sig <= _SIG_MAXSIG and sig > 0;
-}
-
-pub const sigset_t = extern struct {
- __bits: [_SIG_WORDS]u32,
-};
-
-pub fn raise(sig: i32) usize {
- return errnoWrap(c.raise(sig));
-}
-
-pub const Stat = c.Stat;
-pub const dirent = c.dirent;
-pub const timespec = c.timespec;
-
-pub fn fstat(fd: i32, buf: *c.Stat) usize {
- return errnoWrap(c.fstat(fd, buf));
-}
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-// TODO avoid libc dependency
-pub fn kqueue() usize {
- return errnoWrap(c.kqueue());
-}
-
-// TODO avoid libc dependency
-pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
- return errnoWrap(c.kevent(
- kq,
- changelist.ptr,
- @intCast(c_int, changelist.len),
- eventlist.ptr,
- @intCast(c_int, eventlist.len),
- timeout,
- ));
-}
-
-// TODO avoid libc dependency
-pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
- return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
-}
-
-// TODO avoid libc dependency
-
-/// Takes the return value from a syscall and formats it back in the way
-/// that the kernel represents it to libc. Errno was a mistake, let's make
-/// it go away forever.
-fn errnoWrap(value: isize) usize {
- return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
-}
diff --git a/std/os/path.zig b/std/os/path.zig
index 290f8ba17ff2a0681ae725bc637412c622d84fd2..b68ff32408ccd68fcc43e8228558fb3288146553 100644
--- a/std/os/path.zig
+++ b/std/os/path.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const debug = std.debug;
diff --git a/std/os/test.zig b/std/os/test.zig
index b2a4d966518477291333ae4ecd422f5fbbacd892..ab21ea1568b0f2d90f1d9e4a93d3eb7ce04876c7 100644
--- a/std/os/test.zig
+++ b/std/os/test.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const os = std.os;
const expect = std.testing.expect;
const io = std.io;
diff --git a/std/os/time.zig b/std/os/time.zig
index bce6f265defe5dedf9d7776657e8a5c65e87c47c..66ceedb1b614ec628f8814f1195c20b15c1084a3 100644
--- a/std/os/time.zig
+++ b/std/os/time.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const debug = std.debug;
diff --git a/std/os/windows.zig b/std/os/windows.zig
new file mode 100644
index 0000000000000000000000000000000000000000..96274632ce1c927c07fe5863098038dce96fc2ba
--- /dev/null
+++ b/std/os/windows.zig
@@ -0,0 +1,399 @@
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const maxInt = std.math.maxInt;
+
+pub use @import("windows/advapi32.zig");
+pub use @import("windows/kernel32.zig");
+pub use @import("windows/ntdll.zig");
+pub use @import("windows/ole32.zig");
+pub use @import("windows/shell32.zig");
+
+test "import" {
+ _ = @import("windows/util.zig");
+}
+
+pub const ERROR = @import("windows/error.zig");
+
+pub const SHORT = c_short;
+pub const BOOL = c_int;
+pub const BOOLEAN = BYTE;
+pub const BYTE = u8;
+pub const CHAR = u8;
+pub const DWORD = u32;
+pub const FLOAT = f32;
+pub const HANDLE = *c_void;
+pub const HCRYPTPROV = ULONG_PTR;
+pub const HINSTANCE = *@OpaqueType();
+pub const HMODULE = *@OpaqueType();
+pub const FARPROC = *@OpaqueType();
+pub const INT = c_int;
+pub const LPBYTE = *BYTE;
+pub const LPCH = *CHAR;
+pub const LPCSTR = [*]const CHAR;
+pub const LPCTSTR = [*]const TCHAR;
+pub const LPCVOID = *const c_void;
+pub const LPDWORD = *DWORD;
+pub const LPSTR = [*]CHAR;
+pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
+pub const LPVOID = *c_void;
+pub const LPWSTR = [*]WCHAR;
+pub const LPCWSTR = [*]const WCHAR;
+pub const PVOID = *c_void;
+pub const PWSTR = [*]WCHAR;
+pub const SIZE_T = usize;
+pub const TCHAR = if (UNICODE) WCHAR else u8;
+pub const UINT = c_uint;
+pub const ULONG_PTR = usize;
+pub const DWORD_PTR = ULONG_PTR;
+pub const UNICODE = false;
+pub const WCHAR = u16;
+pub const WORD = u16;
+pub const LARGE_INTEGER = i64;
+pub const ULONG = u32;
+pub const LONG = i32;
+pub const ULONGLONG = u64;
+pub const LONGLONG = i64;
+
+pub const TRUE = 1;
+pub const FALSE = 0;
+
+/// The standard input device. Initially, this is the console input buffer, CONIN$.
+pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
+
+/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
+pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
+
+/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
+pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
+
+pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
+
+pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
+
+pub const OVERLAPPED = extern struct {
+ Internal: ULONG_PTR,
+ InternalHigh: ULONG_PTR,
+ Offset: DWORD,
+ OffsetHigh: DWORD,
+ hEvent: ?HANDLE,
+};
+pub const LPOVERLAPPED = *OVERLAPPED;
+
+pub const MAX_PATH = 260;
+
+// TODO issue #305
+pub const FILE_INFO_BY_HANDLE_CLASS = u32;
+pub const FileBasicInfo = 0;
+pub const FileStandardInfo = 1;
+pub const FileNameInfo = 2;
+pub const FileRenameInfo = 3;
+pub const FileDispositionInfo = 4;
+pub const FileAllocationInfo = 5;
+pub const FileEndOfFileInfo = 6;
+pub const FileStreamInfo = 7;
+pub const FileCompressionInfo = 8;
+pub const FileAttributeTagInfo = 9;
+pub const FileIdBothDirectoryInfo = 10;
+pub const FileIdBothDirectoryRestartInfo = 11;
+pub const FileIoPriorityHintInfo = 12;
+pub const FileRemoteProtocolInfo = 13;
+pub const FileFullDirectoryInfo = 14;
+pub const FileFullDirectoryRestartInfo = 15;
+pub const FileStorageInfo = 16;
+pub const FileAlignmentInfo = 17;
+pub const FileIdInfo = 18;
+pub const FileIdExtdDirectoryInfo = 19;
+pub const FileIdExtdDirectoryRestartInfo = 20;
+
+pub const FILE_NAME_INFO = extern struct {
+ FileNameLength: DWORD,
+ FileName: [1]WCHAR,
+};
+
+/// Return the normalized drive name. This is the default.
+pub const FILE_NAME_NORMALIZED = 0x0;
+
+/// Return the opened file name (not normalized).
+pub const FILE_NAME_OPENED = 0x8;
+
+/// Return the path with the drive letter. This is the default.
+pub const VOLUME_NAME_DOS = 0x0;
+
+/// Return the path with a volume GUID path instead of the drive name.
+pub const VOLUME_NAME_GUID = 0x1;
+
+/// Return the path with no drive information.
+pub const VOLUME_NAME_NONE = 0x4;
+
+/// Return the path with the volume device path.
+pub const VOLUME_NAME_NT = 0x2;
+
+pub const SECURITY_ATTRIBUTES = extern struct {
+ nLength: DWORD,
+ lpSecurityDescriptor: ?*c_void,
+ bInheritHandle: BOOL,
+};
+pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
+pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
+
+pub const GENERIC_READ = 0x80000000;
+pub const GENERIC_WRITE = 0x40000000;
+pub const GENERIC_EXECUTE = 0x20000000;
+pub const GENERIC_ALL = 0x10000000;
+
+pub const FILE_SHARE_DELETE = 0x00000004;
+pub const FILE_SHARE_READ = 0x00000001;
+pub const FILE_SHARE_WRITE = 0x00000002;
+
+pub const CREATE_ALWAYS = 2;
+pub const CREATE_NEW = 1;
+pub const OPEN_ALWAYS = 4;
+pub const OPEN_EXISTING = 3;
+pub const TRUNCATE_EXISTING = 5;
+
+pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
+pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
+pub const FILE_ATTRIBUTE_DEVICE = 0x40;
+pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
+pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
+pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
+pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
+pub const FILE_ATTRIBUTE_NORMAL = 0x80;
+pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
+pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
+pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
+pub const FILE_ATTRIBUTE_READONLY = 0x1;
+pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
+pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
+pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
+pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
+pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
+pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
+pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
+
+pub const PROCESS_INFORMATION = extern struct {
+ hProcess: HANDLE,
+ hThread: HANDLE,
+ dwProcessId: DWORD,
+ dwThreadId: DWORD,
+};
+
+pub const STARTUPINFOW = extern struct {
+ cb: DWORD,
+ lpReserved: ?LPWSTR,
+ lpDesktop: ?LPWSTR,
+ lpTitle: ?LPWSTR,
+ dwX: DWORD,
+ dwY: DWORD,
+ dwXSize: DWORD,
+ dwYSize: DWORD,
+ dwXCountChars: DWORD,
+ dwYCountChars: DWORD,
+ dwFillAttribute: DWORD,
+ dwFlags: DWORD,
+ wShowWindow: WORD,
+ cbReserved2: WORD,
+ lpReserved2: ?LPBYTE,
+ hStdInput: ?HANDLE,
+ hStdOutput: ?HANDLE,
+ hStdError: ?HANDLE,
+};
+
+pub const STARTF_FORCEONFEEDBACK = 0x00000040;
+pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
+pub const STARTF_PREVENTPINNING = 0x00002000;
+pub const STARTF_RUNFULLSCREEN = 0x00000020;
+pub const STARTF_TITLEISAPPID = 0x00001000;
+pub const STARTF_TITLEISLINKNAME = 0x00000800;
+pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
+pub const STARTF_USECOUNTCHARS = 0x00000008;
+pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
+pub const STARTF_USEHOTKEY = 0x00000200;
+pub const STARTF_USEPOSITION = 0x00000004;
+pub const STARTF_USESHOWWINDOW = 0x00000001;
+pub const STARTF_USESIZE = 0x00000002;
+pub const STARTF_USESTDHANDLES = 0x00000100;
+
+pub const INFINITE = 4294967295;
+
+pub const WAIT_ABANDONED = 0x00000080;
+pub const WAIT_OBJECT_0 = 0x00000000;
+pub const WAIT_TIMEOUT = 0x00000102;
+pub const WAIT_FAILED = 0xFFFFFFFF;
+
+pub const HANDLE_FLAG_INHERIT = 0x00000001;
+pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
+
+pub const MOVEFILE_COPY_ALLOWED = 2;
+pub const MOVEFILE_CREATE_HARDLINK = 16;
+pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
+pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
+pub const MOVEFILE_REPLACE_EXISTING = 1;
+pub const MOVEFILE_WRITE_THROUGH = 8;
+
+pub const FILE_BEGIN = 0;
+pub const FILE_CURRENT = 1;
+pub const FILE_END = 2;
+
+pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
+pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
+pub const HEAP_NO_SERIALIZE = 0x00000001;
+
+pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
+pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
+
+pub const WIN32_FIND_DATAW = extern struct {
+ dwFileAttributes: DWORD,
+ ftCreationTime: FILETIME,
+ ftLastAccessTime: FILETIME,
+ ftLastWriteTime: FILETIME,
+ nFileSizeHigh: DWORD,
+ nFileSizeLow: DWORD,
+ dwReserved0: DWORD,
+ dwReserved1: DWORD,
+ cFileName: [260]u16,
+ cAlternateFileName: [14]u16,
+};
+
+pub const FILETIME = extern struct {
+ dwLowDateTime: DWORD,
+ dwHighDateTime: DWORD,
+};
+
+pub const SYSTEM_INFO = extern struct {
+ anon1: extern union {
+ dwOemId: DWORD,
+ anon2: extern struct {
+ wProcessorArchitecture: WORD,
+ wReserved: WORD,
+ },
+ },
+ dwPageSize: DWORD,
+ lpMinimumApplicationAddress: LPVOID,
+ lpMaximumApplicationAddress: LPVOID,
+ dwActiveProcessorMask: DWORD_PTR,
+ dwNumberOfProcessors: DWORD,
+ dwProcessorType: DWORD,
+ dwAllocationGranularity: DWORD,
+ wProcessorLevel: WORD,
+ wProcessorRevision: WORD,
+};
+
+pub const HRESULT = c_long;
+
+pub const KNOWNFOLDERID = GUID;
+pub const GUID = extern struct {
+ Data1: c_ulong,
+ Data2: c_ushort,
+ Data3: c_ushort,
+ Data4: [8]u8,
+
+ pub fn parse(str: []const u8) GUID {
+ var guid: GUID = undefined;
+ var index: usize = 0;
+ assert(str[index] == '{');
+ index += 1;
+
+ guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
+ index += 8;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+ guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ var i: usize = 2;
+ while (i < guid.Data4.len) : (i += 1) {
+ guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+ }
+
+ assert(str[index] == '}');
+ index += 1;
+ return guid;
+ }
+};
+
+pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
+
+pub const KF_FLAG_DEFAULT = 0;
+pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
+pub const KF_FLAG_CREATE = 32768;
+pub const KF_FLAG_DONT_VERIFY = 16384;
+pub const KF_FLAG_DONT_UNEXPAND = 8192;
+pub const KF_FLAG_NO_ALIAS = 4096;
+pub const KF_FLAG_INIT = 2048;
+pub const KF_FLAG_DEFAULT_PATH = 1024;
+pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
+pub const KF_FLAG_SIMPLE_IDLIST = 256;
+pub const KF_FLAG_ALIAS_ONLY = -2147483648;
+
+pub const S_OK = 0;
+pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
+pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
+pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
+pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
+pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
+pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
+pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
+pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
+pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
+pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
+
+pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
+pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
+pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
+pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
+pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
+pub const FILE_FLAG_OVERLAPPED = 0x40000000;
+pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
+pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
+pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
+pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
+pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
+
+pub const SMALL_RECT = extern struct {
+ Left: SHORT,
+ Top: SHORT,
+ Right: SHORT,
+ Bottom: SHORT,
+};
+
+pub const COORD = extern struct {
+ X: SHORT,
+ Y: SHORT,
+};
+
+pub const CREATE_UNICODE_ENVIRONMENT = 1024;
+
+pub const TLS_OUT_OF_INDEXES = 4294967295;
+pub const IMAGE_TLS_DIRECTORY = extern struct {
+ StartAddressOfRawData: usize,
+ EndAddressOfRawData: usize,
+ AddressOfIndex: usize,
+ AddressOfCallBacks: usize,
+ SizeOfZeroFill: u32,
+ Characteristics: u32,
+};
+pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
+pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
+
+pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
diff --git a/std/os/windows/advapi32.zig b/std/os/windows/advapi32.zig
index 185c1424c6fae99b3ff0140f9c36e7083e3f391b..9672767500a11ceb7e06f3928cbd3e5d34e6f0a9 100644
--- a/std/os/windows/advapi32.zig
+++ b/std/os/windows/advapi32.zig
@@ -1,4 +1,4 @@
-use @import("index.zig");
+use @import("../windows.zig");
pub const PROV_RSA_FULL = 1;
diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig
deleted file mode 100644
index 8e9ed8b8dbfabc6dbc555e5ff8779440d9002a72..0000000000000000000000000000000000000000
--- a/std/os/windows/index.zig
+++ /dev/null
@@ -1,399 +0,0 @@
-const std = @import("../../index.zig");
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-
-pub use @import("advapi32.zig");
-pub use @import("kernel32.zig");
-pub use @import("ntdll.zig");
-pub use @import("ole32.zig");
-pub use @import("shell32.zig");
-
-test "import" {
- _ = @import("util.zig");
-}
-
-pub const ERROR = @import("error.zig");
-
-pub const SHORT = c_short;
-pub const BOOL = c_int;
-pub const BOOLEAN = BYTE;
-pub const BYTE = u8;
-pub const CHAR = u8;
-pub const DWORD = u32;
-pub const FLOAT = f32;
-pub const HANDLE = *c_void;
-pub const HCRYPTPROV = ULONG_PTR;
-pub const HINSTANCE = *@OpaqueType();
-pub const HMODULE = *@OpaqueType();
-pub const FARPROC = *@OpaqueType();
-pub const INT = c_int;
-pub const LPBYTE = *BYTE;
-pub const LPCH = *CHAR;
-pub const LPCSTR = [*]const CHAR;
-pub const LPCTSTR = [*]const TCHAR;
-pub const LPCVOID = *const c_void;
-pub const LPDWORD = *DWORD;
-pub const LPSTR = [*]CHAR;
-pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
-pub const LPVOID = *c_void;
-pub const LPWSTR = [*]WCHAR;
-pub const LPCWSTR = [*]const WCHAR;
-pub const PVOID = *c_void;
-pub const PWSTR = [*]WCHAR;
-pub const SIZE_T = usize;
-pub const TCHAR = if (UNICODE) WCHAR else u8;
-pub const UINT = c_uint;
-pub const ULONG_PTR = usize;
-pub const DWORD_PTR = ULONG_PTR;
-pub const UNICODE = false;
-pub const WCHAR = u16;
-pub const WORD = u16;
-pub const LARGE_INTEGER = i64;
-pub const ULONG = u32;
-pub const LONG = i32;
-pub const ULONGLONG = u64;
-pub const LONGLONG = i64;
-
-pub const TRUE = 1;
-pub const FALSE = 0;
-
-/// The standard input device. Initially, this is the console input buffer, CONIN$.
-pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
-
-/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
-pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
-
-/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
-pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
-
-pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
-
-pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
-
-pub const OVERLAPPED = extern struct {
- Internal: ULONG_PTR,
- InternalHigh: ULONG_PTR,
- Offset: DWORD,
- OffsetHigh: DWORD,
- hEvent: ?HANDLE,
-};
-pub const LPOVERLAPPED = *OVERLAPPED;
-
-pub const MAX_PATH = 260;
-
-// TODO issue #305
-pub const FILE_INFO_BY_HANDLE_CLASS = u32;
-pub const FileBasicInfo = 0;
-pub const FileStandardInfo = 1;
-pub const FileNameInfo = 2;
-pub const FileRenameInfo = 3;
-pub const FileDispositionInfo = 4;
-pub const FileAllocationInfo = 5;
-pub const FileEndOfFileInfo = 6;
-pub const FileStreamInfo = 7;
-pub const FileCompressionInfo = 8;
-pub const FileAttributeTagInfo = 9;
-pub const FileIdBothDirectoryInfo = 10;
-pub const FileIdBothDirectoryRestartInfo = 11;
-pub const FileIoPriorityHintInfo = 12;
-pub const FileRemoteProtocolInfo = 13;
-pub const FileFullDirectoryInfo = 14;
-pub const FileFullDirectoryRestartInfo = 15;
-pub const FileStorageInfo = 16;
-pub const FileAlignmentInfo = 17;
-pub const FileIdInfo = 18;
-pub const FileIdExtdDirectoryInfo = 19;
-pub const FileIdExtdDirectoryRestartInfo = 20;
-
-pub const FILE_NAME_INFO = extern struct {
- FileNameLength: DWORD,
- FileName: [1]WCHAR,
-};
-
-/// Return the normalized drive name. This is the default.
-pub const FILE_NAME_NORMALIZED = 0x0;
-
-/// Return the opened file name (not normalized).
-pub const FILE_NAME_OPENED = 0x8;
-
-/// Return the path with the drive letter. This is the default.
-pub const VOLUME_NAME_DOS = 0x0;
-
-/// Return the path with a volume GUID path instead of the drive name.
-pub const VOLUME_NAME_GUID = 0x1;
-
-/// Return the path with no drive information.
-pub const VOLUME_NAME_NONE = 0x4;
-
-/// Return the path with the volume device path.
-pub const VOLUME_NAME_NT = 0x2;
-
-pub const SECURITY_ATTRIBUTES = extern struct {
- nLength: DWORD,
- lpSecurityDescriptor: ?*c_void,
- bInheritHandle: BOOL,
-};
-pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
-pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
-
-pub const GENERIC_READ = 0x80000000;
-pub const GENERIC_WRITE = 0x40000000;
-pub const GENERIC_EXECUTE = 0x20000000;
-pub const GENERIC_ALL = 0x10000000;
-
-pub const FILE_SHARE_DELETE = 0x00000004;
-pub const FILE_SHARE_READ = 0x00000001;
-pub const FILE_SHARE_WRITE = 0x00000002;
-
-pub const CREATE_ALWAYS = 2;
-pub const CREATE_NEW = 1;
-pub const OPEN_ALWAYS = 4;
-pub const OPEN_EXISTING = 3;
-pub const TRUNCATE_EXISTING = 5;
-
-pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
-pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
-pub const FILE_ATTRIBUTE_DEVICE = 0x40;
-pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
-pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
-pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
-pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
-pub const FILE_ATTRIBUTE_NORMAL = 0x80;
-pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
-pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
-pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
-pub const FILE_ATTRIBUTE_READONLY = 0x1;
-pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
-pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
-pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
-pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
-pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
-pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
-pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
-
-pub const PROCESS_INFORMATION = extern struct {
- hProcess: HANDLE,
- hThread: HANDLE,
- dwProcessId: DWORD,
- dwThreadId: DWORD,
-};
-
-pub const STARTUPINFOW = extern struct {
- cb: DWORD,
- lpReserved: ?LPWSTR,
- lpDesktop: ?LPWSTR,
- lpTitle: ?LPWSTR,
- dwX: DWORD,
- dwY: DWORD,
- dwXSize: DWORD,
- dwYSize: DWORD,
- dwXCountChars: DWORD,
- dwYCountChars: DWORD,
- dwFillAttribute: DWORD,
- dwFlags: DWORD,
- wShowWindow: WORD,
- cbReserved2: WORD,
- lpReserved2: ?LPBYTE,
- hStdInput: ?HANDLE,
- hStdOutput: ?HANDLE,
- hStdError: ?HANDLE,
-};
-
-pub const STARTF_FORCEONFEEDBACK = 0x00000040;
-pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
-pub const STARTF_PREVENTPINNING = 0x00002000;
-pub const STARTF_RUNFULLSCREEN = 0x00000020;
-pub const STARTF_TITLEISAPPID = 0x00001000;
-pub const STARTF_TITLEISLINKNAME = 0x00000800;
-pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
-pub const STARTF_USECOUNTCHARS = 0x00000008;
-pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
-pub const STARTF_USEHOTKEY = 0x00000200;
-pub const STARTF_USEPOSITION = 0x00000004;
-pub const STARTF_USESHOWWINDOW = 0x00000001;
-pub const STARTF_USESIZE = 0x00000002;
-pub const STARTF_USESTDHANDLES = 0x00000100;
-
-pub const INFINITE = 4294967295;
-
-pub const WAIT_ABANDONED = 0x00000080;
-pub const WAIT_OBJECT_0 = 0x00000000;
-pub const WAIT_TIMEOUT = 0x00000102;
-pub const WAIT_FAILED = 0xFFFFFFFF;
-
-pub const HANDLE_FLAG_INHERIT = 0x00000001;
-pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
-
-pub const MOVEFILE_COPY_ALLOWED = 2;
-pub const MOVEFILE_CREATE_HARDLINK = 16;
-pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
-pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
-pub const MOVEFILE_REPLACE_EXISTING = 1;
-pub const MOVEFILE_WRITE_THROUGH = 8;
-
-pub const FILE_BEGIN = 0;
-pub const FILE_CURRENT = 1;
-pub const FILE_END = 2;
-
-pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
-pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
-pub const HEAP_NO_SERIALIZE = 0x00000001;
-
-pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
-pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
-
-pub const WIN32_FIND_DATAW = extern struct {
- dwFileAttributes: DWORD,
- ftCreationTime: FILETIME,
- ftLastAccessTime: FILETIME,
- ftLastWriteTime: FILETIME,
- nFileSizeHigh: DWORD,
- nFileSizeLow: DWORD,
- dwReserved0: DWORD,
- dwReserved1: DWORD,
- cFileName: [260]u16,
- cAlternateFileName: [14]u16,
-};
-
-pub const FILETIME = extern struct {
- dwLowDateTime: DWORD,
- dwHighDateTime: DWORD,
-};
-
-pub const SYSTEM_INFO = extern struct {
- anon1: extern union {
- dwOemId: DWORD,
- anon2: extern struct {
- wProcessorArchitecture: WORD,
- wReserved: WORD,
- },
- },
- dwPageSize: DWORD,
- lpMinimumApplicationAddress: LPVOID,
- lpMaximumApplicationAddress: LPVOID,
- dwActiveProcessorMask: DWORD_PTR,
- dwNumberOfProcessors: DWORD,
- dwProcessorType: DWORD,
- dwAllocationGranularity: DWORD,
- wProcessorLevel: WORD,
- wProcessorRevision: WORD,
-};
-
-pub const HRESULT = c_long;
-
-pub const KNOWNFOLDERID = GUID;
-pub const GUID = extern struct {
- Data1: c_ulong,
- Data2: c_ushort,
- Data3: c_ushort,
- Data4: [8]u8,
-
- pub fn parse(str: []const u8) GUID {
- var guid: GUID = undefined;
- var index: usize = 0;
- assert(str[index] == '{');
- index += 1;
-
- guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
- index += 8;
-
- assert(str[index] == '-');
- index += 1;
-
- guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
- index += 4;
-
- assert(str[index] == '-');
- index += 1;
-
- guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
- index += 4;
-
- assert(str[index] == '-');
- index += 1;
-
- guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
- guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
-
- assert(str[index] == '-');
- index += 1;
-
- var i: usize = 2;
- while (i < guid.Data4.len) : (i += 1) {
- guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
- }
-
- assert(str[index] == '}');
- index += 1;
- return guid;
- }
-};
-
-pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
-
-pub const KF_FLAG_DEFAULT = 0;
-pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
-pub const KF_FLAG_CREATE = 32768;
-pub const KF_FLAG_DONT_VERIFY = 16384;
-pub const KF_FLAG_DONT_UNEXPAND = 8192;
-pub const KF_FLAG_NO_ALIAS = 4096;
-pub const KF_FLAG_INIT = 2048;
-pub const KF_FLAG_DEFAULT_PATH = 1024;
-pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
-pub const KF_FLAG_SIMPLE_IDLIST = 256;
-pub const KF_FLAG_ALIAS_ONLY = -2147483648;
-
-pub const S_OK = 0;
-pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
-pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
-pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
-pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
-pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
-pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
-pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
-pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
-pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
-pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
-
-pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
-pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
-pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
-pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
-pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
-pub const FILE_FLAG_OVERLAPPED = 0x40000000;
-pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
-pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
-pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
-pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
-pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
-
-pub const SMALL_RECT = extern struct {
- Left: SHORT,
- Top: SHORT,
- Right: SHORT,
- Bottom: SHORT,
-};
-
-pub const COORD = extern struct {
- X: SHORT,
- Y: SHORT,
-};
-
-pub const CREATE_UNICODE_ENVIRONMENT = 1024;
-
-pub const TLS_OUT_OF_INDEXES = 4294967295;
-pub const IMAGE_TLS_DIRECTORY = extern struct {
- StartAddressOfRawData: usize,
- EndAddressOfRawData: usize,
- AddressOfIndex: usize,
- AddressOfCallBacks: usize,
- SizeOfZeroFill: u32,
- Characteristics: u32,
-};
-pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
-pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
-
-pub const PIMAGE_TLS_CALLBACK = ?extern fn(PVOID, DWORD, PVOID) void;
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
index ce8443de02c3ed5a773b898f9e0cdca51650b8cb..64a97ca87d0216f4e6c3e149bc77d28b7251e7dd 100644
--- a/std/os/windows/kernel32.zig
+++ b/std/os/windows/kernel32.zig
@@ -1,4 +1,4 @@
-use @import("index.zig");
+use @import("../windows.zig");
pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
@@ -262,12 +262,10 @@ pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
-pub const INIT_ONCE_FN = extern fn(InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
+pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
pub const RTL_RUN_ONCE = extern struct {
Ptr: ?*c_void,
};
-pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE {
- .Ptr = null,
-};
+pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
diff --git a/std/os/windows/ntdll.zig b/std/os/windows/ntdll.zig
index acb78a59f4d7115457ddc835d582ea7bca245f2a..1b63c1e7ec4c67de26bc03884beea7c2db4c531c 100644
--- a/std/os/windows/ntdll.zig
+++ b/std/os/windows/ntdll.zig
@@ -1,3 +1,3 @@
-use @import("index.zig");
+use @import("../windows.zig");
pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
diff --git a/std/os/windows/ole32.zig b/std/os/windows/ole32.zig
index 8f34b45bbf3acad676b378e084bd852994c7ac72..1ecfecba3c69b3e3d36719b3f44069b386325031 100644
--- a/std/os/windows/ole32.zig
+++ b/std/os/windows/ole32.zig
@@ -1,4 +1,4 @@
-use @import("index.zig");
+use @import("../windows.zig");
pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
pub extern "ole32" stdcallcc fn CoUninitialize() void;
diff --git a/std/os/windows/shell32.zig b/std/os/windows/shell32.zig
index 139babc7a8eba05a1392cc529e1a834cd13219a2..c299e01f17c0fd2bc2971e0c9ee86194ea24346d 100644
--- a/std/os/windows/shell32.zig
+++ b/std/os/windows/shell32.zig
@@ -1,4 +1,4 @@
-use @import("index.zig");
+use @import("../windows.zig");
pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
diff --git a/std/os/windows/tls.zig b/std/os/windows/tls.zig
deleted file mode 100644
index 9e62a7c5c660bf61450a3fa4268a2ecafae62c82..0000000000000000000000000000000000000000
--- a/std/os/windows/tls.zig
+++ /dev/null
@@ -1,36 +0,0 @@
-const std = @import("../../index.zig");
-
-export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES;
-export var _tls_start: u8 linksection(".tls") = 0;
-export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
-export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
-export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
-
-// TODO this is how I would like it to be expressed
-// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate
-// why they do that.
-//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY {
-// .StartAddressOfRawData = @ptrToInt(&_tls_start),
-// .EndAddressOfRawData = @ptrToInt(&_tls_end),
-// .AddressOfIndex = @ptrToInt(&_tls_index),
-// .AddressOfCallBacks = @ptrToInt(__xl_a),
-// .SizeOfZeroFill = 0,
-// .Characteristics = 0,
-//};
-// This is the workaround because we can't do @ptrToInt at comptime like that.
-pub const IMAGE_TLS_DIRECTORY = extern struct {
- StartAddressOfRawData: *c_void,
- EndAddressOfRawData: *c_void,
- AddressOfIndex: *c_void,
- AddressOfCallBacks: *c_void,
- SizeOfZeroFill: u32,
- Characteristics: u32,
-};
-export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY {
- .StartAddressOfRawData = &_tls_start,
- .EndAddressOfRawData = &_tls_end,
- .AddressOfIndex = &_tls_index,
- .AddressOfCallBacks = &__xl_a,
- .SizeOfZeroFill = 0,
- .Characteristics = 0,
-};
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
index 849c15a6f59f97effa9fad11fc6358181d238501..09523430516c453334f6ba7fbfd6326f782581c7 100644
--- a/std/os/windows/util.zig
+++ b/std/os/windows/util.zig
@@ -1,4 +1,4 @@
-const std = @import("../../index.zig");
+const std = @import("../../std.zig");
const builtin = @import("builtin");
const os = std.os;
const unicode = std.unicode;
diff --git a/std/os/zen.zig b/std/os/zen.zig
index 76c4df9d62a32cf009ed3f96fa634ee7c7dcdff2..0564956b2451dd8bd7ac460e4e036cd066c620c0 100644
--- a/std/os/zen.zig
+++ b/std/os/zen.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
//////////////////////////
diff --git a/std/pdb.zig b/std/pdb.zig
index b6e48ad2f76524c0f1fe6ce838b1155d7c916dd9..2b02a8487105232179381fa3d61806b80c35b7af 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
-const std = @import("index.zig");
+const std = @import("std.zig");
const io = std.io;
const math = std.math;
const mem = std.mem;
@@ -12,7 +12,6 @@ const ArrayList = std.ArrayList;
// Note: most of this is based on information gathered from LLVM source code,
// documentation and/or contributors.
-
// https://llvm.org/docs/PDB/DbiStream.html#stream-header
pub const DbiStreamHeader = packed struct {
VersionSignature: i32,
@@ -393,10 +392,9 @@ pub const LineNumberEntry = packed struct {
Flags: u32,
/// TODO runtime crash when I make the actual type of Flags this
- const Flags = packed struct {
+ pub const Flags = packed struct {
/// Start line number
Start: u24,
-
/// Delta of lines to the end of the expression. Still unclear.
// TODO figure out the point of this field.
End: u7,
diff --git a/std/priority_queue.zig b/std/priority_queue.zig
index 33b5a963c66c6638e7a42ef12ded36340a115efe..d2c493af3e8c5c74b9ff1a7ff7b2c8ebbe618071 100644
--- a/std/priority_queue.zig
+++ b/std/priority_queue.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const Allocator = std.mem.Allocator;
const debug = std.debug;
const expect = std.testing.expect;
diff --git a/std/rand.zig b/std/rand.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a2fdfed6fd5787127d3c1dbb57d77d5bd5acc1e2
--- /dev/null
+++ b/std/rand.zig
@@ -0,0 +1,1005 @@
+// The engines provided here should be initialized from an external source. For now, getRandomBytes
+// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
+// a normal PRNG will be faster and use substantially less stack space.
+//
+// ```
+// var buf: [8]u8 = undefined;
+// try std.os.getRandomBytes(buf[0..]);
+// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
+//
+// var r = DefaultPrng.init(seed);
+//
+// const s = r.random.int(u64);
+// ```
+//
+// TODO(tiehuis): Benchmark these against other reference implementations.
+
+const std = @import("std.zig");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+const expect = std.testing.expect;
+const mem = std.mem;
+const math = std.math;
+const ziggurat = @import("rand/ziggurat.zig");
+const maxInt = std.math.maxInt;
+
+// When you need fast unbiased random numbers
+pub const DefaultPrng = Xoroshiro128;
+
+// When you need cryptographically secure random numbers
+pub const DefaultCsprng = Isaac64;
+
+pub const Random = struct {
+ fillFn: fn (r: *Random, buf: []u8) void,
+
+ /// Read random bytes into the specified buffer until full.
+ pub fn bytes(r: *Random, buf: []u8) void {
+ r.fillFn(r, buf);
+ }
+
+ pub fn boolean(r: *Random) bool {
+ return r.int(u1) != 0;
+ }
+
+ /// Returns a random int `i` such that `0 <= i <= maxInt(T)`.
+ /// `i` is evenly distributed.
+ pub fn int(r: *Random, comptime T: type) T {
+ const UnsignedT = @IntType(false, T.bit_count);
+ const ByteAlignedT = @IntType(false, @divTrunc(T.bit_count + 7, 8) * 8);
+
+ var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined;
+ r.bytes(rand_bytes[0..]);
+
+ // use LE instead of native endian for better portability maybe?
+ // TODO: endian portability is pointless if the underlying prng isn't endian portable.
+ // TODO: document the endian portability of this library.
+ const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
+ const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
+ return @bitCast(T, unsigned_result);
+ }
+
+ /// Constant-time implementation off ::uintLessThan.
+ /// The results of this function may be biased.
+ pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
+ comptime assert(T.is_signed == false);
+ comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
+ assert(0 < less_than);
+ if (T.bit_count <= 32) {
+ return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
+ } else {
+ return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
+ }
+ }
+
+ /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
+ /// This function assumes that the underlying ::fillFn produces evenly distributed values.
+ /// Within this assumption, the runtime of this function is exponentially distributed.
+ /// If ::fillFn were backed by a true random generator,
+ /// the runtime of this function would technically be unbounded.
+ /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
+ /// this function is guaranteed to return.
+ /// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
+ pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
+ comptime assert(T.is_signed == false);
+ comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
+ assert(0 < less_than);
+ // Small is typically u32
+ const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
+ // Large is typically u64
+ const Large = @IntType(false, Small.bit_count * 2);
+
+ // adapted from:
+ // http://www.pcg-random.org/posts/bounded-rands.html
+ // "Lemire's (with an extra tweak from me)"
+ var x: Small = r.int(Small);
+ var m: Large = Large(x) * Large(less_than);
+ var l: Small = @truncate(Small, m);
+ if (l < less_than) {
+ // TODO: workaround for https://github.com/ziglang/zig/issues/1770
+ // should be:
+ // var t: Small = -%less_than;
+ var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
+
+ if (t >= less_than) {
+ t -= less_than;
+ if (t >= less_than) {
+ t %= less_than;
+ }
+ }
+ while (l < t) {
+ x = r.int(Small);
+ m = Large(x) * Large(less_than);
+ l = @truncate(Small, m);
+ }
+ }
+ return @intCast(T, m >> Small.bit_count);
+ }
+
+ /// Constant-time implementation off ::uintAtMost.
+ /// The results of this function may be biased.
+ pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
+ assert(T.is_signed == false);
+ if (at_most == maxInt(T)) {
+ // have the full range
+ return r.int(T);
+ }
+ return r.uintLessThanBiased(T, at_most + 1);
+ }
+
+ /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
+ /// See ::uintLessThan, which this function uses in most cases,
+ /// for commentary on the runtime of this function.
+ pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {
+ assert(T.is_signed == false);
+ if (at_most == maxInt(T)) {
+ // have the full range
+ return r.int(T);
+ }
+ return r.uintLessThan(T, at_most + 1);
+ }
+
+ /// Constant-time implementation off ::intRangeLessThan.
+ /// The results of this function may be biased.
+ pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
+ assert(at_least < less_than);
+ if (T.is_signed) {
+ // Two's complement makes this math pretty easy.
+ const UnsignedT = @IntType(false, T.bit_count);
+ const lo = @bitCast(UnsignedT, at_least);
+ const hi = @bitCast(UnsignedT, less_than);
+ const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
+ return @bitCast(T, result);
+ } else {
+ // The signed implementation would work fine, but we can use stricter arithmetic operators here.
+ return at_least + r.uintLessThanBiased(T, less_than - at_least);
+ }
+ }
+
+ /// Returns an evenly distributed random integer `at_least <= i < less_than`.
+ /// See ::uintLessThan, which this function uses in most cases,
+ /// for commentary on the runtime of this function.
+ pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {
+ assert(at_least < less_than);
+ if (T.is_signed) {
+ // Two's complement makes this math pretty easy.
+ const UnsignedT = @IntType(false, T.bit_count);
+ const lo = @bitCast(UnsignedT, at_least);
+ const hi = @bitCast(UnsignedT, less_than);
+ const result = lo +% r.uintLessThan(UnsignedT, hi -% lo);
+ return @bitCast(T, result);
+ } else {
+ // The signed implementation would work fine, but we can use stricter arithmetic operators here.
+ return at_least + r.uintLessThan(T, less_than - at_least);
+ }
+ }
+
+ /// Constant-time implementation off ::intRangeAtMostBiased.
+ /// The results of this function may be biased.
+ pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
+ assert(at_least <= at_most);
+ if (T.is_signed) {
+ // Two's complement makes this math pretty easy.
+ const UnsignedT = @IntType(false, T.bit_count);
+ const lo = @bitCast(UnsignedT, at_least);
+ const hi = @bitCast(UnsignedT, at_most);
+ const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
+ return @bitCast(T, result);
+ } else {
+ // The signed implementation would work fine, but we can use stricter arithmetic operators here.
+ return at_least + r.uintAtMostBiased(T, at_most - at_least);
+ }
+ }
+
+ /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
+ /// See ::uintLessThan, which this function uses in most cases,
+ /// for commentary on the runtime of this function.
+ pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {
+ assert(at_least <= at_most);
+ if (T.is_signed) {
+ // Two's complement makes this math pretty easy.
+ const UnsignedT = @IntType(false, T.bit_count);
+ const lo = @bitCast(UnsignedT, at_least);
+ const hi = @bitCast(UnsignedT, at_most);
+ const result = lo +% r.uintAtMost(UnsignedT, hi -% lo);
+ return @bitCast(T, result);
+ } else {
+ // The signed implementation would work fine, but we can use stricter arithmetic operators here.
+ return at_least + r.uintAtMost(T, at_most - at_least);
+ }
+ }
+
+ /// TODO: deprecated. use ::boolean or ::int instead.
+ pub fn scalar(r: *Random, comptime T: type) T {
+ return if (T == bool) r.boolean() else r.int(T);
+ }
+
+ /// TODO: deprecated. renamed to ::intRangeLessThan
+ pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
+ return r.intRangeLessThan(T, start, end);
+ }
+
+ /// Return a floating point value evenly distributed in the range [0, 1).
+ pub fn float(r: *Random, comptime T: type) T {
+ // Generate a uniform value between [1, 2) and scale down to [0, 1).
+ // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
+ switch (T) {
+ f32 => {
+ const s = r.int(u32);
+ const repr = (0x7f << 23) | (s >> 9);
+ return @bitCast(f32, repr) - 1.0;
+ },
+ f64 => {
+ const s = r.int(u64);
+ const repr = (0x3ff << 52) | (s >> 12);
+ return @bitCast(f64, repr) - 1.0;
+ },
+ else => @compileError("unknown floating point type"),
+ }
+ }
+
+ /// Return a floating point value normally distributed with mean = 0, stddev = 1.
+ ///
+ /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
+ pub fn floatNorm(r: *Random, comptime T: type) T {
+ const value = ziggurat.next_f64(r, ziggurat.NormDist);
+ switch (T) {
+ f32 => return @floatCast(f32, value),
+ f64 => return value,
+ else => @compileError("unknown floating point type"),
+ }
+ }
+
+ /// Return an exponentially distributed float with a rate parameter of 1.
+ ///
+ /// To use a different rate parameter, use: floatExp(...) / desiredRate.
+ pub fn floatExp(r: *Random, comptime T: type) T {
+ const value = ziggurat.next_f64(r, ziggurat.ExpDist);
+ switch (T) {
+ f32 => return @floatCast(f32, value),
+ f64 => return value,
+ else => @compileError("unknown floating point type"),
+ }
+ }
+
+ /// Shuffle a slice into a random order.
+ pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
+ if (buf.len < 2) {
+ return;
+ }
+
+ var i: usize = 0;
+ while (i < buf.len - 1) : (i += 1) {
+ const j = r.intRangeLessThan(usize, i, buf.len);
+ mem.swap(T, &buf[i], &buf[j]);
+ }
+ }
+};
+
+/// Convert a random integer 0 <= random_int <= maxValue(T),
+/// into an integer 0 <= result < less_than.
+/// This function introduces a minor bias.
+pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
+ comptime assert(T.is_signed == false);
+ const T2 = @IntType(false, T.bit_count * 2);
+
+ // adapted from:
+ // http://www.pcg-random.org/posts/bounded-rands.html
+ // "Integer Multiplication (Biased)"
+ var m: T2 = T2(random_int) * T2(less_than);
+ return @intCast(T, m >> T.bit_count);
+}
+
+const SequentialPrng = struct {
+ const Self = @This();
+ random: Random,
+ next_value: u8,
+
+ pub fn init() Self {
+ return Self{
+ .random = Random{ .fillFn = fill },
+ .next_value = 0,
+ };
+ }
+
+ fn fill(r: *Random, buf: []u8) void {
+ const self = @fieldParentPtr(Self, "random", r);
+ for (buf) |*b| {
+ b.* = self.next_value;
+ }
+ self.next_value +%= 1;
+ }
+};
+
+test "Random int" {
+ testRandomInt();
+ comptime testRandomInt();
+}
+fn testRandomInt() void {
+ var r = SequentialPrng.init();
+
+ expect(r.random.int(u0) == 0);
+
+ r.next_value = 0;
+ expect(r.random.int(u1) == 0);
+ expect(r.random.int(u1) == 1);
+ expect(r.random.int(u2) == 2);
+ expect(r.random.int(u2) == 3);
+ expect(r.random.int(u2) == 0);
+
+ r.next_value = 0xff;
+ expect(r.random.int(u8) == 0xff);
+ r.next_value = 0x11;
+ expect(r.random.int(u8) == 0x11);
+
+ r.next_value = 0xff;
+ expect(r.random.int(u32) == 0xffffffff);
+ r.next_value = 0x11;
+ expect(r.random.int(u32) == 0x11111111);
+
+ r.next_value = 0xff;
+ expect(r.random.int(i32) == -1);
+ r.next_value = 0x11;
+ expect(r.random.int(i32) == 0x11111111);
+
+ r.next_value = 0xff;
+ expect(r.random.int(i8) == -1);
+ r.next_value = 0x11;
+ expect(r.random.int(i8) == 0x11);
+
+ r.next_value = 0xff;
+ expect(r.random.int(u33) == 0x1ffffffff);
+ r.next_value = 0xff;
+ expect(r.random.int(i1) == -1);
+ r.next_value = 0xff;
+ expect(r.random.int(i2) == -1);
+ r.next_value = 0xff;
+ expect(r.random.int(i33) == -1);
+}
+
+test "Random boolean" {
+ testRandomBoolean();
+ comptime testRandomBoolean();
+}
+fn testRandomBoolean() void {
+ var r = SequentialPrng.init();
+ expect(r.random.boolean() == false);
+ expect(r.random.boolean() == true);
+ expect(r.random.boolean() == false);
+ expect(r.random.boolean() == true);
+}
+
+test "Random intLessThan" {
+ @setEvalBranchQuota(10000);
+ testRandomIntLessThan();
+ comptime testRandomIntLessThan();
+}
+fn testRandomIntLessThan() void {
+ var r = SequentialPrng.init();
+ r.next_value = 0xff;
+ expect(r.random.uintLessThan(u8, 4) == 3);
+ expect(r.next_value == 0);
+ expect(r.random.uintLessThan(u8, 4) == 0);
+ expect(r.next_value == 1);
+
+ r.next_value = 0;
+ expect(r.random.uintLessThan(u64, 32) == 0);
+
+ // trigger the bias rejection code path
+ r.next_value = 0;
+ expect(r.random.uintLessThan(u8, 3) == 0);
+ // verify we incremented twice
+ expect(r.next_value == 2);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(i3, -4, 0) == -1);
+ r.next_value = 0xff;
+ expect(r.random.intRangeLessThan(i3, -2, 2) == 1);
+}
+
+test "Random intAtMost" {
+ @setEvalBranchQuota(10000);
+ testRandomIntAtMost();
+ comptime testRandomIntAtMost();
+}
+fn testRandomIntAtMost() void {
+ var r = SequentialPrng.init();
+ r.next_value = 0xff;
+ expect(r.random.uintAtMost(u8, 3) == 3);
+ expect(r.next_value == 0);
+ expect(r.random.uintAtMost(u8, 3) == 0);
+
+ // trigger the bias rejection code path
+ r.next_value = 0;
+ expect(r.random.uintAtMost(u8, 2) == 0);
+ // verify we incremented twice
+ expect(r.next_value == 2);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
+
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(i3, -4, -1) == -1);
+ r.next_value = 0xff;
+ expect(r.random.intRangeAtMost(i3, -2, 1) == 1);
+
+ expect(r.random.uintAtMost(u0, 0) == 0);
+}
+
+test "Random Biased" {
+ var r = DefaultPrng.init(0);
+ // Not thoroughly checking the logic here.
+ // Just want to execute all the paths with different types.
+
+ expect(r.random.uintLessThanBiased(u1, 1) == 0);
+ expect(r.random.uintLessThanBiased(u32, 10) < 10);
+ expect(r.random.uintLessThanBiased(u64, 20) < 20);
+
+ expect(r.random.uintAtMostBiased(u0, 0) == 0);
+ expect(r.random.uintAtMostBiased(u1, 0) <= 0);
+ expect(r.random.uintAtMostBiased(u32, 10) <= 10);
+ expect(r.random.uintAtMostBiased(u64, 20) <= 20);
+
+ expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
+ expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
+ expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
+ expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
+ expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
+ expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
+
+ // uncomment for broken module error:
+ //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
+ expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
+ expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
+ expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
+ expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
+ expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
+ expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
+}
+
+// Generator to extend 64-bit seed values into longer sequences.
+//
+// The number of cycles is thus limited to 64-bits regardless of the engine, but this
+// is still plenty for practical purposes.
+const SplitMix64 = struct {
+ s: u64,
+
+ pub fn init(seed: u64) SplitMix64 {
+ return SplitMix64{ .s = seed };
+ }
+
+ pub fn next(self: *SplitMix64) u64 {
+ self.s +%= 0x9e3779b97f4a7c15;
+
+ var z = self.s;
+ z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
+ z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
+ return z ^ (z >> 31);
+ }
+};
+
+test "splitmix64 sequence" {
+ var r = SplitMix64.init(0xaeecf86f7878dd75);
+
+ const seq = []const u64{
+ 0x5dbd39db0178eb44,
+ 0xa9900fb66b397da3,
+ 0x5c1a28b1aeebcf5c,
+ 0x64a963238f776912,
+ 0xc6d4177b21d1c0ab,
+ 0xb2cbdbdb5ea35394,
+ };
+
+ for (seq) |s| {
+ expect(s == r.next());
+ }
+}
+
+// PCG32 - http://www.pcg-random.org/
+//
+// PRNG
+pub const Pcg = struct {
+ const default_multiplier = 6364136223846793005;
+
+ random: Random,
+
+ s: u64,
+ i: u64,
+
+ pub fn init(init_s: u64) Pcg {
+ var pcg = Pcg{
+ .random = Random{ .fillFn = fill },
+ .s = undefined,
+ .i = undefined,
+ };
+
+ pcg.seed(init_s);
+ return pcg;
+ }
+
+ fn next(self: *Pcg) u32 {
+ const l = self.s;
+ self.s = l *% default_multiplier +% (self.i | 1);
+
+ const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
+ const rot = @intCast(u32, l >> 59);
+
+ return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
+ }
+
+ fn seed(self: *Pcg, init_s: u64) void {
+ // Pcg requires 128-bits of seed.
+ var gen = SplitMix64.init(init_s);
+ self.seedTwo(gen.next(), gen.next());
+ }
+
+ fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
+ self.s = 0;
+ self.i = (init_s << 1) | 1;
+ self.s = self.s *% default_multiplier +% self.i;
+ self.s +%= init_i;
+ self.s = self.s *% default_multiplier +% self.i;
+ }
+
+ fn fill(r: *Random, buf: []u8) void {
+ const self = @fieldParentPtr(Pcg, "random", r);
+
+ var i: usize = 0;
+ const aligned_len = buf.len - (buf.len & 7);
+
+ // Complete 4 byte segments.
+ while (i < aligned_len) : (i += 4) {
+ var n = self.next();
+ comptime var j: usize = 0;
+ inline while (j < 4) : (j += 1) {
+ buf[i + j] = @truncate(u8, n);
+ n >>= 8;
+ }
+ }
+
+ // Remaining. (cuts the stream)
+ if (i != buf.len) {
+ var n = self.next();
+ while (i < buf.len) : (i += 1) {
+ buf[i] = @truncate(u8, n);
+ n >>= 4;
+ }
+ }
+ }
+};
+
+test "pcg sequence" {
+ var r = Pcg.init(0);
+ const s0: u64 = 0x9394bf54ce5d79de;
+ const s1: u64 = 0x84e9c579ef59bbf7;
+ r.seedTwo(s0, s1);
+
+ const seq = []const u32{
+ 2881561918,
+ 3063928540,
+ 1199791034,
+ 2487695858,
+ 1479648952,
+ 3247963454,
+ };
+
+ for (seq) |s| {
+ expect(s == r.next());
+ }
+}
+
+// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
+//
+// PRNG
+pub const Xoroshiro128 = struct {
+ random: Random,
+
+ s: [2]u64,
+
+ pub fn init(init_s: u64) Xoroshiro128 {
+ var x = Xoroshiro128{
+ .random = Random{ .fillFn = fill },
+ .s = undefined,
+ };
+
+ x.seed(init_s);
+ return x;
+ }
+
+ fn next(self: *Xoroshiro128) u64 {
+ const s0 = self.s[0];
+ var s1 = self.s[1];
+ const r = s0 +% s1;
+
+ s1 ^= s0;
+ self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
+ self.s[1] = math.rotl(u64, s1, u8(36));
+
+ return r;
+ }
+
+ // Skip 2^64 places ahead in the sequence
+ fn jump(self: *Xoroshiro128) void {
+ var s0: u64 = 0;
+ var s1: u64 = 0;
+
+ const table = []const u64{
+ 0xbeac0467eba5facb,
+ 0xd86b048b86aa9922,
+ };
+
+ inline for (table) |entry| {
+ var b: usize = 0;
+ while (b < 64) : (b += 1) {
+ if ((entry & (u64(1) << @intCast(u6, b))) != 0) {
+ s0 ^= self.s[0];
+ s1 ^= self.s[1];
+ }
+ _ = self.next();
+ }
+ }
+
+ self.s[0] = s0;
+ self.s[1] = s1;
+ }
+
+ fn seed(self: *Xoroshiro128, init_s: u64) void {
+ // Xoroshiro requires 128-bits of seed.
+ var gen = SplitMix64.init(init_s);
+
+ self.s[0] = gen.next();
+ self.s[1] = gen.next();
+ }
+
+ fn fill(r: *Random, buf: []u8) void {
+ const self = @fieldParentPtr(Xoroshiro128, "random", r);
+
+ var i: usize = 0;
+ const aligned_len = buf.len - (buf.len & 7);
+
+ // Complete 8 byte segments.
+ while (i < aligned_len) : (i += 8) {
+ var n = self.next();
+ comptime var j: usize = 0;
+ inline while (j < 8) : (j += 1) {
+ buf[i + j] = @truncate(u8, n);
+ n >>= 8;
+ }
+ }
+
+ // Remaining. (cuts the stream)
+ if (i != buf.len) {
+ var n = self.next();
+ while (i < buf.len) : (i += 1) {
+ buf[i] = @truncate(u8, n);
+ n >>= 8;
+ }
+ }
+ }
+};
+
+test "xoroshiro sequence" {
+ var r = Xoroshiro128.init(0);
+ r.s[0] = 0xaeecf86f7878dd75;
+ r.s[1] = 0x01cd153642e72622;
+
+ const seq1 = []const u64{
+ 0xb0ba0da5bb600397,
+ 0x18a08afde614dccc,
+ 0xa2635b956a31b929,
+ 0xabe633c971efa045,
+ 0x9ac19f9706ca3cac,
+ 0xf62b426578c1e3fb,
+ };
+
+ for (seq1) |s| {
+ expect(s == r.next());
+ }
+
+ r.jump();
+
+ const seq2 = []const u64{
+ 0x95344a13556d3e22,
+ 0xb4fb32dafa4d00df,
+ 0xb2011d9ccdcfe2dd,
+ 0x05679a9b2119b908,
+ 0xa860a1da7c9cd8a0,
+ 0x658a96efe3f86550,
+ };
+
+ for (seq2) |s| {
+ expect(s == r.next());
+ }
+}
+
+// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
+//
+// CSPRNG
+//
+// Follows the general idea of the implementation from here with a few shortcuts.
+// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
+pub const Isaac64 = struct {
+ random: Random,
+
+ r: [256]u64,
+ m: [256]u64,
+ a: u64,
+ b: u64,
+ c: u64,
+ i: usize,
+
+ pub fn init(init_s: u64) Isaac64 {
+ var isaac = Isaac64{
+ .random = Random{ .fillFn = fill },
+ .r = undefined,
+ .m = undefined,
+ .a = undefined,
+ .b = undefined,
+ .c = undefined,
+ .i = undefined,
+ };
+
+ // seed == 0 => same result as the unseeded reference implementation
+ isaac.seed(init_s, 1);
+ return isaac;
+ }
+
+ fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
+ const x = self.m[base + m1];
+ self.a = mix +% self.m[base + m2];
+
+ const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
+ self.m[base + m1] = y;
+
+ self.b = x +% self.m[(y >> 11) % self.m.len];
+ self.r[self.r.len - 1 - base - m1] = self.b;
+ }
+
+ fn refill(self: *Isaac64) void {
+ const midpoint = self.r.len / 2;
+
+ self.c +%= 1;
+ self.b +%= self.c;
+
+ {
+ var i: usize = 0;
+ while (i < midpoint) : (i += 4) {
+ self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
+ self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
+ self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
+ self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
+ }
+ }
+
+ {
+ var i: usize = 0;
+ while (i < midpoint) : (i += 4) {
+ self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
+ self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
+ self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
+ self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
+ }
+ }
+
+ self.i = 0;
+ }
+
+ fn next(self: *Isaac64) u64 {
+ if (self.i >= self.r.len) {
+ self.refill();
+ }
+
+ const value = self.r[self.i];
+ self.i += 1;
+ return value;
+ }
+
+ fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
+ // We ignore the multi-pass requirement since we don't currently expose full access to
+ // seeding the self.m array completely.
+ mem.set(u64, self.m[0..], 0);
+ self.m[0] = init_s;
+
+ // prescrambled golden ratio constants
+ var a = []const u64{
+ 0x647c4677a2884b7c,
+ 0xb9f8b322c73ac862,
+ 0x8c0ea5053d4712a0,
+ 0xb29b2e824a595524,
+ 0x82f053db8355e0ce,
+ 0x48fe4a0fa5a09315,
+ 0xae985bf2cbfc89ed,
+ 0x98f5704f6c44c0ab,
+ };
+
+ comptime var i: usize = 0;
+ inline while (i < rounds) : (i += 1) {
+ var j: usize = 0;
+ while (j < self.m.len) : (j += 8) {
+ comptime var x1: usize = 0;
+ inline while (x1 < 8) : (x1 += 1) {
+ a[x1] +%= self.m[j + x1];
+ }
+
+ a[0] -%= a[4];
+ a[5] ^= a[7] >> 9;
+ a[7] +%= a[0];
+ a[1] -%= a[5];
+ a[6] ^= a[0] << 9;
+ a[0] +%= a[1];
+ a[2] -%= a[6];
+ a[7] ^= a[1] >> 23;
+ a[1] +%= a[2];
+ a[3] -%= a[7];
+ a[0] ^= a[2] << 15;
+ a[2] +%= a[3];
+ a[4] -%= a[0];
+ a[1] ^= a[3] >> 14;
+ a[3] +%= a[4];
+ a[5] -%= a[1];
+ a[2] ^= a[4] << 20;
+ a[4] +%= a[5];
+ a[6] -%= a[2];
+ a[3] ^= a[5] >> 17;
+ a[5] +%= a[6];
+ a[7] -%= a[3];
+ a[4] ^= a[6] << 14;
+ a[6] +%= a[7];
+
+ comptime var x2: usize = 0;
+ inline while (x2 < 8) : (x2 += 1) {
+ self.m[j + x2] = a[x2];
+ }
+ }
+ }
+
+ mem.set(u64, self.r[0..], 0);
+ self.a = 0;
+ self.b = 0;
+ self.c = 0;
+ self.i = self.r.len; // trigger refill on first value
+ }
+
+ fn fill(r: *Random, buf: []u8) void {
+ const self = @fieldParentPtr(Isaac64, "random", r);
+
+ var i: usize = 0;
+ const aligned_len = buf.len - (buf.len & 7);
+
+ // Fill complete 64-byte segments
+ while (i < aligned_len) : (i += 8) {
+ var n = self.next();
+ comptime var j: usize = 0;
+ inline while (j < 8) : (j += 1) {
+ buf[i + j] = @truncate(u8, n);
+ n >>= 8;
+ }
+ }
+
+ // Fill trailing, ignoring excess (cut the stream).
+ if (i != buf.len) {
+ var n = self.next();
+ while (i < buf.len) : (i += 1) {
+ buf[i] = @truncate(u8, n);
+ n >>= 8;
+ }
+ }
+ }
+};
+
+test "isaac64 sequence" {
+ var r = Isaac64.init(0);
+
+ // from reference implementation
+ const seq = []const u64{
+ 0xf67dfba498e4937c,
+ 0x84a5066a9204f380,
+ 0xfee34bd5f5514dbb,
+ 0x4d1664739b8f80d6,
+ 0x8607459ab52a14aa,
+ 0x0e78bc5a98529e49,
+ 0xfe5332822ad13777,
+ 0x556c27525e33d01a,
+ 0x08643ca615f3149f,
+ 0xd0771faf3cb04714,
+ 0x30e86f68a37b008d,
+ 0x3074ebc0488a3adf,
+ 0x270645ea7a2790bc,
+ 0x5601a0a8d3763c6a,
+ 0x2f83071f53f325dd,
+ 0xb9090f3d42d2d2ea,
+ };
+
+ for (seq) |s| {
+ expect(s == r.next());
+ }
+}
+
+// Actual Random helper function tests, pcg engine is assumed correct.
+test "Random float" {
+ var prng = DefaultPrng.init(0);
+
+ var i: usize = 0;
+ while (i < 1000) : (i += 1) {
+ const val1 = prng.random.float(f32);
+ expect(val1 >= 0.0);
+ expect(val1 < 1.0);
+
+ const val2 = prng.random.float(f64);
+ expect(val2 >= 0.0);
+ expect(val2 < 1.0);
+ }
+}
+
+test "Random shuffle" {
+ var prng = DefaultPrng.init(0);
+
+ var seq = []const u8{ 0, 1, 2, 3, 4 };
+ var seen = []bool{false} ** 5;
+
+ var i: usize = 0;
+ while (i < 1000) : (i += 1) {
+ prng.random.shuffle(u8, seq[0..]);
+ seen[seq[0]] = true;
+ expect(sumArray(seq[0..]) == 10);
+ }
+
+ // we should see every entry at the head at least once
+ for (seen) |e| {
+ expect(e == true);
+ }
+}
+
+fn sumArray(s: []const u8) u32 {
+ var r: u32 = 0;
+ for (s) |e|
+ r += e;
+ return r;
+}
+
+test "Random range" {
+ var prng = DefaultPrng.init(0);
+ testRange(&prng.random, -4, 3);
+ testRange(&prng.random, -4, -1);
+ testRange(&prng.random, 10, 14);
+ testRange(&prng.random, -0x80, 0x7f);
+}
+
+fn testRange(r: *Random, start: i8, end: i8) void {
+ testRangeBias(r, start, end, true);
+ testRangeBias(r, start, end, false);
+}
+fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
+ const count = @intCast(usize, i32(end) - i32(start));
+ var values_buffer = []bool{false} ** 0x100;
+ const values = values_buffer[0..count];
+ var i: usize = 0;
+ while (i < count) {
+ const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
+ const index = @intCast(usize, value - start);
+ if (!values[index]) {
+ i += 1;
+ values[index] = true;
+ }
+ }
+}
diff --git a/std/rand/index.zig b/std/rand/index.zig
deleted file mode 100644
index 12dd763aeecf85883071c2e2721afb2a9481be16..0000000000000000000000000000000000000000
--- a/std/rand/index.zig
+++ /dev/null
@@ -1,1005 +0,0 @@
-// The engines provided here should be initialized from an external source. For now, getRandomBytes
-// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
-// a normal PRNG will be faster and use substantially less stack space.
-//
-// ```
-// var buf: [8]u8 = undefined;
-// try std.os.getRandomBytes(buf[0..]);
-// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
-//
-// var r = DefaultPrng.init(seed);
-//
-// const s = r.random.int(u64);
-// ```
-//
-// TODO(tiehuis): Benchmark these against other reference implementations.
-
-const std = @import("../index.zig");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-const expect = std.testing.expect;
-const mem = std.mem;
-const math = std.math;
-const ziggurat = @import("ziggurat.zig");
-const maxInt = std.math.maxInt;
-
-// When you need fast unbiased random numbers
-pub const DefaultPrng = Xoroshiro128;
-
-// When you need cryptographically secure random numbers
-pub const DefaultCsprng = Isaac64;
-
-pub const Random = struct {
- fillFn: fn (r: *Random, buf: []u8) void,
-
- /// Read random bytes into the specified buffer until full.
- pub fn bytes(r: *Random, buf: []u8) void {
- r.fillFn(r, buf);
- }
-
- pub fn boolean(r: *Random) bool {
- return r.int(u1) != 0;
- }
-
- /// Returns a random int `i` such that `0 <= i <= maxInt(T)`.
- /// `i` is evenly distributed.
- pub fn int(r: *Random, comptime T: type) T {
- const UnsignedT = @IntType(false, T.bit_count);
- const ByteAlignedT = @IntType(false, @divTrunc(T.bit_count + 7, 8) * 8);
-
- var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined;
- r.bytes(rand_bytes[0..]);
-
- // use LE instead of native endian for better portability maybe?
- // TODO: endian portability is pointless if the underlying prng isn't endian portable.
- // TODO: document the endian portability of this library.
- const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
- const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
- return @bitCast(T, unsigned_result);
- }
-
- /// Constant-time implementation off ::uintLessThan.
- /// The results of this function may be biased.
- pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
- comptime assert(T.is_signed == false);
- comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
- assert(0 < less_than);
- if (T.bit_count <= 32) {
- return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
- } else {
- return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
- }
- }
-
- /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
- /// This function assumes that the underlying ::fillFn produces evenly distributed values.
- /// Within this assumption, the runtime of this function is exponentially distributed.
- /// If ::fillFn were backed by a true random generator,
- /// the runtime of this function would technically be unbounded.
- /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
- /// this function is guaranteed to return.
- /// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
- pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
- comptime assert(T.is_signed == false);
- comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
- assert(0 < less_than);
- // Small is typically u32
- const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
- // Large is typically u64
- const Large = @IntType(false, Small.bit_count * 2);
-
- // adapted from:
- // http://www.pcg-random.org/posts/bounded-rands.html
- // "Lemire's (with an extra tweak from me)"
- var x: Small = r.int(Small);
- var m: Large = Large(x) * Large(less_than);
- var l: Small = @truncate(Small, m);
- if (l < less_than) {
- // TODO: workaround for https://github.com/ziglang/zig/issues/1770
- // should be:
- // var t: Small = -%less_than;
- var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
-
- if (t >= less_than) {
- t -= less_than;
- if (t >= less_than) {
- t %= less_than;
- }
- }
- while (l < t) {
- x = r.int(Small);
- m = Large(x) * Large(less_than);
- l = @truncate(Small, m);
- }
- }
- return @intCast(T, m >> Small.bit_count);
- }
-
- /// Constant-time implementation off ::uintAtMost.
- /// The results of this function may be biased.
- pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
- assert(T.is_signed == false);
- if (at_most == maxInt(T)) {
- // have the full range
- return r.int(T);
- }
- return r.uintLessThanBiased(T, at_most + 1);
- }
-
- /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
- /// See ::uintLessThan, which this function uses in most cases,
- /// for commentary on the runtime of this function.
- pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {
- assert(T.is_signed == false);
- if (at_most == maxInt(T)) {
- // have the full range
- return r.int(T);
- }
- return r.uintLessThan(T, at_most + 1);
- }
-
- /// Constant-time implementation off ::intRangeLessThan.
- /// The results of this function may be biased.
- pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
- assert(at_least < less_than);
- if (T.is_signed) {
- // Two's complement makes this math pretty easy.
- const UnsignedT = @IntType(false, T.bit_count);
- const lo = @bitCast(UnsignedT, at_least);
- const hi = @bitCast(UnsignedT, less_than);
- const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
- return @bitCast(T, result);
- } else {
- // The signed implementation would work fine, but we can use stricter arithmetic operators here.
- return at_least + r.uintLessThanBiased(T, less_than - at_least);
- }
- }
-
- /// Returns an evenly distributed random integer `at_least <= i < less_than`.
- /// See ::uintLessThan, which this function uses in most cases,
- /// for commentary on the runtime of this function.
- pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {
- assert(at_least < less_than);
- if (T.is_signed) {
- // Two's complement makes this math pretty easy.
- const UnsignedT = @IntType(false, T.bit_count);
- const lo = @bitCast(UnsignedT, at_least);
- const hi = @bitCast(UnsignedT, less_than);
- const result = lo +% r.uintLessThan(UnsignedT, hi -% lo);
- return @bitCast(T, result);
- } else {
- // The signed implementation would work fine, but we can use stricter arithmetic operators here.
- return at_least + r.uintLessThan(T, less_than - at_least);
- }
- }
-
- /// Constant-time implementation off ::intRangeAtMostBiased.
- /// The results of this function may be biased.
- pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
- assert(at_least <= at_most);
- if (T.is_signed) {
- // Two's complement makes this math pretty easy.
- const UnsignedT = @IntType(false, T.bit_count);
- const lo = @bitCast(UnsignedT, at_least);
- const hi = @bitCast(UnsignedT, at_most);
- const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
- return @bitCast(T, result);
- } else {
- // The signed implementation would work fine, but we can use stricter arithmetic operators here.
- return at_least + r.uintAtMostBiased(T, at_most - at_least);
- }
- }
-
- /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
- /// See ::uintLessThan, which this function uses in most cases,
- /// for commentary on the runtime of this function.
- pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {
- assert(at_least <= at_most);
- if (T.is_signed) {
- // Two's complement makes this math pretty easy.
- const UnsignedT = @IntType(false, T.bit_count);
- const lo = @bitCast(UnsignedT, at_least);
- const hi = @bitCast(UnsignedT, at_most);
- const result = lo +% r.uintAtMost(UnsignedT, hi -% lo);
- return @bitCast(T, result);
- } else {
- // The signed implementation would work fine, but we can use stricter arithmetic operators here.
- return at_least + r.uintAtMost(T, at_most - at_least);
- }
- }
-
- /// TODO: deprecated. use ::boolean or ::int instead.
- pub fn scalar(r: *Random, comptime T: type) T {
- return if (T == bool) r.boolean() else r.int(T);
- }
-
- /// TODO: deprecated. renamed to ::intRangeLessThan
- pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
- return r.intRangeLessThan(T, start, end);
- }
-
- /// Return a floating point value evenly distributed in the range [0, 1).
- pub fn float(r: *Random, comptime T: type) T {
- // Generate a uniform value between [1, 2) and scale down to [0, 1).
- // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
- switch (T) {
- f32 => {
- const s = r.int(u32);
- const repr = (0x7f << 23) | (s >> 9);
- return @bitCast(f32, repr) - 1.0;
- },
- f64 => {
- const s = r.int(u64);
- const repr = (0x3ff << 52) | (s >> 12);
- return @bitCast(f64, repr) - 1.0;
- },
- else => @compileError("unknown floating point type"),
- }
- }
-
- /// Return a floating point value normally distributed with mean = 0, stddev = 1.
- ///
- /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
- pub fn floatNorm(r: *Random, comptime T: type) T {
- const value = ziggurat.next_f64(r, ziggurat.NormDist);
- switch (T) {
- f32 => return @floatCast(f32, value),
- f64 => return value,
- else => @compileError("unknown floating point type"),
- }
- }
-
- /// Return an exponentially distributed float with a rate parameter of 1.
- ///
- /// To use a different rate parameter, use: floatExp(...) / desiredRate.
- pub fn floatExp(r: *Random, comptime T: type) T {
- const value = ziggurat.next_f64(r, ziggurat.ExpDist);
- switch (T) {
- f32 => return @floatCast(f32, value),
- f64 => return value,
- else => @compileError("unknown floating point type"),
- }
- }
-
- /// Shuffle a slice into a random order.
- pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {
- if (buf.len < 2) {
- return;
- }
-
- var i: usize = 0;
- while (i < buf.len - 1) : (i += 1) {
- const j = r.intRangeLessThan(usize, i, buf.len);
- mem.swap(T, &buf[i], &buf[j]);
- }
- }
-};
-
-/// Convert a random integer 0 <= random_int <= maxValue(T),
-/// into an integer 0 <= result < less_than.
-/// This function introduces a minor bias.
-pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
- comptime assert(T.is_signed == false);
- const T2 = @IntType(false, T.bit_count * 2);
-
- // adapted from:
- // http://www.pcg-random.org/posts/bounded-rands.html
- // "Integer Multiplication (Biased)"
- var m: T2 = T2(random_int) * T2(less_than);
- return @intCast(T, m >> T.bit_count);
-}
-
-const SequentialPrng = struct {
- const Self = @This();
- random: Random,
- next_value: u8,
-
- pub fn init() Self {
- return Self{
- .random = Random{ .fillFn = fill },
- .next_value = 0,
- };
- }
-
- fn fill(r: *Random, buf: []u8) void {
- const self = @fieldParentPtr(Self, "random", r);
- for (buf) |*b| {
- b.* = self.next_value;
- }
- self.next_value +%= 1;
- }
-};
-
-test "Random int" {
- testRandomInt();
- comptime testRandomInt();
-}
-fn testRandomInt() void {
- var r = SequentialPrng.init();
-
- expect(r.random.int(u0) == 0);
-
- r.next_value = 0;
- expect(r.random.int(u1) == 0);
- expect(r.random.int(u1) == 1);
- expect(r.random.int(u2) == 2);
- expect(r.random.int(u2) == 3);
- expect(r.random.int(u2) == 0);
-
- r.next_value = 0xff;
- expect(r.random.int(u8) == 0xff);
- r.next_value = 0x11;
- expect(r.random.int(u8) == 0x11);
-
- r.next_value = 0xff;
- expect(r.random.int(u32) == 0xffffffff);
- r.next_value = 0x11;
- expect(r.random.int(u32) == 0x11111111);
-
- r.next_value = 0xff;
- expect(r.random.int(i32) == -1);
- r.next_value = 0x11;
- expect(r.random.int(i32) == 0x11111111);
-
- r.next_value = 0xff;
- expect(r.random.int(i8) == -1);
- r.next_value = 0x11;
- expect(r.random.int(i8) == 0x11);
-
- r.next_value = 0xff;
- expect(r.random.int(u33) == 0x1ffffffff);
- r.next_value = 0xff;
- expect(r.random.int(i1) == -1);
- r.next_value = 0xff;
- expect(r.random.int(i2) == -1);
- r.next_value = 0xff;
- expect(r.random.int(i33) == -1);
-}
-
-test "Random boolean" {
- testRandomBoolean();
- comptime testRandomBoolean();
-}
-fn testRandomBoolean() void {
- var r = SequentialPrng.init();
- expect(r.random.boolean() == false);
- expect(r.random.boolean() == true);
- expect(r.random.boolean() == false);
- expect(r.random.boolean() == true);
-}
-
-test "Random intLessThan" {
- @setEvalBranchQuota(10000);
- testRandomIntLessThan();
- comptime testRandomIntLessThan();
-}
-fn testRandomIntLessThan() void {
- var r = SequentialPrng.init();
- r.next_value = 0xff;
- expect(r.random.uintLessThan(u8, 4) == 3);
- expect(r.next_value == 0);
- expect(r.random.uintLessThan(u8, 4) == 0);
- expect(r.next_value == 1);
-
- r.next_value = 0;
- expect(r.random.uintLessThan(u64, 32) == 0);
-
- // trigger the bias rejection code path
- r.next_value = 0;
- expect(r.random.uintLessThan(u8, 3) == 0);
- // verify we incremented twice
- expect(r.next_value == 2);
-
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
-
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
-
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(i3, -4, 0) == -1);
- r.next_value = 0xff;
- expect(r.random.intRangeLessThan(i3, -2, 2) == 1);
-}
-
-test "Random intAtMost" {
- @setEvalBranchQuota(10000);
- testRandomIntAtMost();
- comptime testRandomIntAtMost();
-}
-fn testRandomIntAtMost() void {
- var r = SequentialPrng.init();
- r.next_value = 0xff;
- expect(r.random.uintAtMost(u8, 3) == 3);
- expect(r.next_value == 0);
- expect(r.random.uintAtMost(u8, 3) == 0);
-
- // trigger the bias rejection code path
- r.next_value = 0;
- expect(r.random.uintAtMost(u8, 2) == 0);
- // verify we incremented twice
- expect(r.next_value == 2);
-
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
-
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
-
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(i3, -4, -1) == -1);
- r.next_value = 0xff;
- expect(r.random.intRangeAtMost(i3, -2, 1) == 1);
-
- expect(r.random.uintAtMost(u0, 0) == 0);
-}
-
-test "Random Biased" {
- var r = DefaultPrng.init(0);
- // Not thoroughly checking the logic here.
- // Just want to execute all the paths with different types.
-
- expect(r.random.uintLessThanBiased(u1, 1) == 0);
- expect(r.random.uintLessThanBiased(u32, 10) < 10);
- expect(r.random.uintLessThanBiased(u64, 20) < 20);
-
- expect(r.random.uintAtMostBiased(u0, 0) == 0);
- expect(r.random.uintAtMostBiased(u1, 0) <= 0);
- expect(r.random.uintAtMostBiased(u32, 10) <= 10);
- expect(r.random.uintAtMostBiased(u64, 20) <= 20);
-
- expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
- expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
- expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
- expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
- expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
- expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
-
- // uncomment for broken module error:
- //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
- expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
- expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
- expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
- expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
- expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
- expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
-}
-
-// Generator to extend 64-bit seed values into longer sequences.
-//
-// The number of cycles is thus limited to 64-bits regardless of the engine, but this
-// is still plenty for practical purposes.
-const SplitMix64 = struct {
- s: u64,
-
- pub fn init(seed: u64) SplitMix64 {
- return SplitMix64{ .s = seed };
- }
-
- pub fn next(self: *SplitMix64) u64 {
- self.s +%= 0x9e3779b97f4a7c15;
-
- var z = self.s;
- z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
- z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
- return z ^ (z >> 31);
- }
-};
-
-test "splitmix64 sequence" {
- var r = SplitMix64.init(0xaeecf86f7878dd75);
-
- const seq = []const u64{
- 0x5dbd39db0178eb44,
- 0xa9900fb66b397da3,
- 0x5c1a28b1aeebcf5c,
- 0x64a963238f776912,
- 0xc6d4177b21d1c0ab,
- 0xb2cbdbdb5ea35394,
- };
-
- for (seq) |s| {
- expect(s == r.next());
- }
-}
-
-// PCG32 - http://www.pcg-random.org/
-//
-// PRNG
-pub const Pcg = struct {
- const default_multiplier = 6364136223846793005;
-
- random: Random,
-
- s: u64,
- i: u64,
-
- pub fn init(init_s: u64) Pcg {
- var pcg = Pcg{
- .random = Random{ .fillFn = fill },
- .s = undefined,
- .i = undefined,
- };
-
- pcg.seed(init_s);
- return pcg;
- }
-
- fn next(self: *Pcg) u32 {
- const l = self.s;
- self.s = l *% default_multiplier +% (self.i | 1);
-
- const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
- const rot = @intCast(u32, l >> 59);
-
- return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
- }
-
- fn seed(self: *Pcg, init_s: u64) void {
- // Pcg requires 128-bits of seed.
- var gen = SplitMix64.init(init_s);
- self.seedTwo(gen.next(), gen.next());
- }
-
- fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
- self.s = 0;
- self.i = (init_s << 1) | 1;
- self.s = self.s *% default_multiplier +% self.i;
- self.s +%= init_i;
- self.s = self.s *% default_multiplier +% self.i;
- }
-
- fn fill(r: *Random, buf: []u8) void {
- const self = @fieldParentPtr(Pcg, "random", r);
-
- var i: usize = 0;
- const aligned_len = buf.len - (buf.len & 7);
-
- // Complete 4 byte segments.
- while (i < aligned_len) : (i += 4) {
- var n = self.next();
- comptime var j: usize = 0;
- inline while (j < 4) : (j += 1) {
- buf[i + j] = @truncate(u8, n);
- n >>= 8;
- }
- }
-
- // Remaining. (cuts the stream)
- if (i != buf.len) {
- var n = self.next();
- while (i < buf.len) : (i += 1) {
- buf[i] = @truncate(u8, n);
- n >>= 4;
- }
- }
- }
-};
-
-test "pcg sequence" {
- var r = Pcg.init(0);
- const s0: u64 = 0x9394bf54ce5d79de;
- const s1: u64 = 0x84e9c579ef59bbf7;
- r.seedTwo(s0, s1);
-
- const seq = []const u32{
- 2881561918,
- 3063928540,
- 1199791034,
- 2487695858,
- 1479648952,
- 3247963454,
- };
-
- for (seq) |s| {
- expect(s == r.next());
- }
-}
-
-// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
-//
-// PRNG
-pub const Xoroshiro128 = struct {
- random: Random,
-
- s: [2]u64,
-
- pub fn init(init_s: u64) Xoroshiro128 {
- var x = Xoroshiro128{
- .random = Random{ .fillFn = fill },
- .s = undefined,
- };
-
- x.seed(init_s);
- return x;
- }
-
- fn next(self: *Xoroshiro128) u64 {
- const s0 = self.s[0];
- var s1 = self.s[1];
- const r = s0 +% s1;
-
- s1 ^= s0;
- self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
- self.s[1] = math.rotl(u64, s1, u8(36));
-
- return r;
- }
-
- // Skip 2^64 places ahead in the sequence
- fn jump(self: *Xoroshiro128) void {
- var s0: u64 = 0;
- var s1: u64 = 0;
-
- const table = []const u64{
- 0xbeac0467eba5facb,
- 0xd86b048b86aa9922,
- };
-
- inline for (table) |entry| {
- var b: usize = 0;
- while (b < 64) : (b += 1) {
- if ((entry & (u64(1) << @intCast(u6, b))) != 0) {
- s0 ^= self.s[0];
- s1 ^= self.s[1];
- }
- _ = self.next();
- }
- }
-
- self.s[0] = s0;
- self.s[1] = s1;
- }
-
- fn seed(self: *Xoroshiro128, init_s: u64) void {
- // Xoroshiro requires 128-bits of seed.
- var gen = SplitMix64.init(init_s);
-
- self.s[0] = gen.next();
- self.s[1] = gen.next();
- }
-
- fn fill(r: *Random, buf: []u8) void {
- const self = @fieldParentPtr(Xoroshiro128, "random", r);
-
- var i: usize = 0;
- const aligned_len = buf.len - (buf.len & 7);
-
- // Complete 8 byte segments.
- while (i < aligned_len) : (i += 8) {
- var n = self.next();
- comptime var j: usize = 0;
- inline while (j < 8) : (j += 1) {
- buf[i + j] = @truncate(u8, n);
- n >>= 8;
- }
- }
-
- // Remaining. (cuts the stream)
- if (i != buf.len) {
- var n = self.next();
- while (i < buf.len) : (i += 1) {
- buf[i] = @truncate(u8, n);
- n >>= 8;
- }
- }
- }
-};
-
-test "xoroshiro sequence" {
- var r = Xoroshiro128.init(0);
- r.s[0] = 0xaeecf86f7878dd75;
- r.s[1] = 0x01cd153642e72622;
-
- const seq1 = []const u64{
- 0xb0ba0da5bb600397,
- 0x18a08afde614dccc,
- 0xa2635b956a31b929,
- 0xabe633c971efa045,
- 0x9ac19f9706ca3cac,
- 0xf62b426578c1e3fb,
- };
-
- for (seq1) |s| {
- expect(s == r.next());
- }
-
- r.jump();
-
- const seq2 = []const u64{
- 0x95344a13556d3e22,
- 0xb4fb32dafa4d00df,
- 0xb2011d9ccdcfe2dd,
- 0x05679a9b2119b908,
- 0xa860a1da7c9cd8a0,
- 0x658a96efe3f86550,
- };
-
- for (seq2) |s| {
- expect(s == r.next());
- }
-}
-
-// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
-//
-// CSPRNG
-//
-// Follows the general idea of the implementation from here with a few shortcuts.
-// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
-pub const Isaac64 = struct {
- random: Random,
-
- r: [256]u64,
- m: [256]u64,
- a: u64,
- b: u64,
- c: u64,
- i: usize,
-
- pub fn init(init_s: u64) Isaac64 {
- var isaac = Isaac64{
- .random = Random{ .fillFn = fill },
- .r = undefined,
- .m = undefined,
- .a = undefined,
- .b = undefined,
- .c = undefined,
- .i = undefined,
- };
-
- // seed == 0 => same result as the unseeded reference implementation
- isaac.seed(init_s, 1);
- return isaac;
- }
-
- fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
- const x = self.m[base + m1];
- self.a = mix +% self.m[base + m2];
-
- const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
- self.m[base + m1] = y;
-
- self.b = x +% self.m[(y >> 11) % self.m.len];
- self.r[self.r.len - 1 - base - m1] = self.b;
- }
-
- fn refill(self: *Isaac64) void {
- const midpoint = self.r.len / 2;
-
- self.c +%= 1;
- self.b +%= self.c;
-
- {
- var i: usize = 0;
- while (i < midpoint) : (i += 4) {
- self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
- self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
- self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
- self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
- }
- }
-
- {
- var i: usize = 0;
- while (i < midpoint) : (i += 4) {
- self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
- self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
- self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
- self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
- }
- }
-
- self.i = 0;
- }
-
- fn next(self: *Isaac64) u64 {
- if (self.i >= self.r.len) {
- self.refill();
- }
-
- const value = self.r[self.i];
- self.i += 1;
- return value;
- }
-
- fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
- // We ignore the multi-pass requirement since we don't currently expose full access to
- // seeding the self.m array completely.
- mem.set(u64, self.m[0..], 0);
- self.m[0] = init_s;
-
- // prescrambled golden ratio constants
- var a = []const u64{
- 0x647c4677a2884b7c,
- 0xb9f8b322c73ac862,
- 0x8c0ea5053d4712a0,
- 0xb29b2e824a595524,
- 0x82f053db8355e0ce,
- 0x48fe4a0fa5a09315,
- 0xae985bf2cbfc89ed,
- 0x98f5704f6c44c0ab,
- };
-
- comptime var i: usize = 0;
- inline while (i < rounds) : (i += 1) {
- var j: usize = 0;
- while (j < self.m.len) : (j += 8) {
- comptime var x1: usize = 0;
- inline while (x1 < 8) : (x1 += 1) {
- a[x1] +%= self.m[j + x1];
- }
-
- a[0] -%= a[4];
- a[5] ^= a[7] >> 9;
- a[7] +%= a[0];
- a[1] -%= a[5];
- a[6] ^= a[0] << 9;
- a[0] +%= a[1];
- a[2] -%= a[6];
- a[7] ^= a[1] >> 23;
- a[1] +%= a[2];
- a[3] -%= a[7];
- a[0] ^= a[2] << 15;
- a[2] +%= a[3];
- a[4] -%= a[0];
- a[1] ^= a[3] >> 14;
- a[3] +%= a[4];
- a[5] -%= a[1];
- a[2] ^= a[4] << 20;
- a[4] +%= a[5];
- a[6] -%= a[2];
- a[3] ^= a[5] >> 17;
- a[5] +%= a[6];
- a[7] -%= a[3];
- a[4] ^= a[6] << 14;
- a[6] +%= a[7];
-
- comptime var x2: usize = 0;
- inline while (x2 < 8) : (x2 += 1) {
- self.m[j + x2] = a[x2];
- }
- }
- }
-
- mem.set(u64, self.r[0..], 0);
- self.a = 0;
- self.b = 0;
- self.c = 0;
- self.i = self.r.len; // trigger refill on first value
- }
-
- fn fill(r: *Random, buf: []u8) void {
- const self = @fieldParentPtr(Isaac64, "random", r);
-
- var i: usize = 0;
- const aligned_len = buf.len - (buf.len & 7);
-
- // Fill complete 64-byte segments
- while (i < aligned_len) : (i += 8) {
- var n = self.next();
- comptime var j: usize = 0;
- inline while (j < 8) : (j += 1) {
- buf[i + j] = @truncate(u8, n);
- n >>= 8;
- }
- }
-
- // Fill trailing, ignoring excess (cut the stream).
- if (i != buf.len) {
- var n = self.next();
- while (i < buf.len) : (i += 1) {
- buf[i] = @truncate(u8, n);
- n >>= 8;
- }
- }
- }
-};
-
-test "isaac64 sequence" {
- var r = Isaac64.init(0);
-
- // from reference implementation
- const seq = []const u64{
- 0xf67dfba498e4937c,
- 0x84a5066a9204f380,
- 0xfee34bd5f5514dbb,
- 0x4d1664739b8f80d6,
- 0x8607459ab52a14aa,
- 0x0e78bc5a98529e49,
- 0xfe5332822ad13777,
- 0x556c27525e33d01a,
- 0x08643ca615f3149f,
- 0xd0771faf3cb04714,
- 0x30e86f68a37b008d,
- 0x3074ebc0488a3adf,
- 0x270645ea7a2790bc,
- 0x5601a0a8d3763c6a,
- 0x2f83071f53f325dd,
- 0xb9090f3d42d2d2ea,
- };
-
- for (seq) |s| {
- expect(s == r.next());
- }
-}
-
-// Actual Random helper function tests, pcg engine is assumed correct.
-test "Random float" {
- var prng = DefaultPrng.init(0);
-
- var i: usize = 0;
- while (i < 1000) : (i += 1) {
- const val1 = prng.random.float(f32);
- expect(val1 >= 0.0);
- expect(val1 < 1.0);
-
- const val2 = prng.random.float(f64);
- expect(val2 >= 0.0);
- expect(val2 < 1.0);
- }
-}
-
-test "Random shuffle" {
- var prng = DefaultPrng.init(0);
-
- var seq = []const u8{ 0, 1, 2, 3, 4 };
- var seen = []bool{false} ** 5;
-
- var i: usize = 0;
- while (i < 1000) : (i += 1) {
- prng.random.shuffle(u8, seq[0..]);
- seen[seq[0]] = true;
- expect(sumArray(seq[0..]) == 10);
- }
-
- // we should see every entry at the head at least once
- for (seen) |e| {
- expect(e == true);
- }
-}
-
-fn sumArray(s: []const u8) u32 {
- var r: u32 = 0;
- for (s) |e|
- r += e;
- return r;
-}
-
-test "Random range" {
- var prng = DefaultPrng.init(0);
- testRange(&prng.random, -4, 3);
- testRange(&prng.random, -4, -1);
- testRange(&prng.random, 10, 14);
- testRange(&prng.random, -0x80, 0x7f);
-}
-
-fn testRange(r: *Random, start: i8, end: i8) void {
- testRangeBias(r, start, end, true);
- testRangeBias(r, start, end, false);
-}
-fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
- const count = @intCast(usize, i32(end) - i32(start));
- var values_buffer = []bool{false} ** 0x100;
- const values = values_buffer[0..count];
- var i: usize = 0;
- while (i < count) {
- const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
- const index = @intCast(usize, value - start);
- if (!values[index]) {
- i += 1;
- values[index] = true;
- }
- }
-}
diff --git a/std/rand/ziggurat.zig b/std/rand/ziggurat.zig
index 0636a5bfc42c3d286f66ea823ff01ecdb152b0f0..995248415be1c35fc8cd60f2e431286eb820199e 100644
--- a/std/rand/ziggurat.zig
+++ b/std/rand/ziggurat.zig
@@ -8,7 +8,7 @@
// NOTE: This seems interesting but reference code is a bit hard to grok:
// https://sbarral.github.io/etf.
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const math = std.math;
const Random = std.rand.Random;
diff --git a/std/rb.zig b/std/rb.zig
index 27e60dca6ab02dba5a4f44902ed1dc2837690a6a..0b28550a131927573bbc5f89550727a3789ecbb6 100644
--- a/std/rb.zig
+++ b/std/rb.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem; // For mem.Compare
diff --git a/std/segmented_list.zig b/std/segmented_list.zig
index 26b7fa48f59909e5b67073f1be48b94f8f1c73a2..0600fbba3fd8c4b321e714f93df4b7346f3ed86f 100644
--- a/std/segmented_list.zig
+++ b/std/segmented_list.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const Allocator = std.mem.Allocator;
diff --git a/std/sort.zig b/std/sort.zig
index 86a6724fee6113aae6849bd01acf65105b726b1b..69dc148f31bcb317ee83051864181890406d55cf 100644
--- a/std/sort.zig
+++ b/std/sort.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig
index 950fd5cbb959bcf13fe9017f4a508851d62fa775..04b29d6709152924c443d3e036ac227dc91a8106 100644
--- a/std/special/bootstrap.zig
+++ b/std/special/bootstrap.zig
@@ -46,7 +46,7 @@ nakedcc fn _start() noreturn {
extern fn WinMainCRTStartup() noreturn {
@setAlignStack(16);
if (!builtin.single_threaded) {
- _ = @import("../os/windows/tls.zig");
+ _ = @import("bootstrap_windows_tls.zig");
}
std.os.windows.ExitProcess(callMain());
}
diff --git a/std/special/bootstrap_windows_tls.zig b/std/special/bootstrap_windows_tls.zig
new file mode 100644
index 0000000000000000000000000000000000000000..71165d355b1f10c88574313910c3a75330acea6a
--- /dev/null
+++ b/std/special/bootstrap_windows_tls.zig
@@ -0,0 +1,36 @@
+const std = @import("std");
+
+export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES;
+export var _tls_start: u8 linksection(".tls") = 0;
+export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
+export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
+export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
+
+// TODO this is how I would like it to be expressed
+// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate
+// why they do that.
+//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY {
+// .StartAddressOfRawData = @ptrToInt(&_tls_start),
+// .EndAddressOfRawData = @ptrToInt(&_tls_end),
+// .AddressOfIndex = @ptrToInt(&_tls_index),
+// .AddressOfCallBacks = @ptrToInt(__xl_a),
+// .SizeOfZeroFill = 0,
+// .Characteristics = 0,
+//};
+// This is the workaround because we can't do @ptrToInt at comptime like that.
+pub const IMAGE_TLS_DIRECTORY = extern struct {
+ StartAddressOfRawData: *c_void,
+ EndAddressOfRawData: *c_void,
+ AddressOfIndex: *c_void,
+ AddressOfCallBacks: *c_void,
+ SizeOfZeroFill: u32,
+ Characteristics: u32,
+};
+export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{
+ .StartAddressOfRawData = &_tls_start,
+ .EndAddressOfRawData = &_tls_end,
+ .AddressOfIndex = &_tls_index,
+ .AddressOfCallBacks = &__xl_a,
+ .SizeOfZeroFill = 0,
+ .Characteristics = 0,
+};
diff --git a/std/special/builtin.zig b/std/special/builtin.zig
index ad50eecc27eaf08e0bd1ea6dd8db53cbdeb9ed07..38c1493ba2584b1ee2f51c514d8a0253bff72c28 100644
--- a/std/special/builtin.zig
+++ b/std/special/builtin.zig
@@ -134,7 +134,7 @@ nakedcc fn clone() void {
}
}
-const math = @import("../math/index.zig");
+const math = std.math;
export fn fmodf(x: f32, y: f32) f32 {
return generic_fmod(f32, x, y);
diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6521dc1aaf8fc44915e1ced8c5efdc323185fae5
--- /dev/null
+++ b/std/special/compiler_rt.zig
@@ -0,0 +1,1038 @@
+const builtin = @import("builtin");
+const is_test = builtin.is_test;
+
+comptime {
+ const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
+ const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
+
+ @export("__letf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
+ @export("__getf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage);
+
+ if (!is_test) {
+ // only create these aliases when not testing
+ @export("__cmptf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
+ @export("__eqtf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
+ @export("__lttf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
+ @export("__netf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage);
+ @export("__gttf2", @import("compiler_rt/comparetf2.zig").__getf2, linkage);
+ @export("__gnu_h2f_ieee", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage);
+ @export("__gnu_f2h_ieee", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage);
+ }
+
+ @export("__unordtf2", @import("compiler_rt/comparetf2.zig").__unordtf2, linkage);
+
+ @export("__addtf3", @import("compiler_rt/addXf3.zig").__addtf3, linkage);
+ @export("__subtf3", @import("compiler_rt/addXf3.zig").__subtf3, linkage);
+
+ @export("__floattitf", @import("compiler_rt/floattitf.zig").__floattitf, linkage);
+ @export("__floattidf", @import("compiler_rt/floattidf.zig").__floattidf, linkage);
+ @export("__floattisf", @import("compiler_rt/floattisf.zig").__floattisf, linkage);
+
+ @export("__floatunditf", @import("compiler_rt/floatunditf.zig").__floatunditf, linkage);
+ @export("__floatunsitf", @import("compiler_rt/floatunsitf.zig").__floatunsitf, linkage);
+
+ @export("__floatuntitf", @import("compiler_rt/floatuntitf.zig").__floatuntitf, linkage);
+ @export("__floatuntidf", @import("compiler_rt/floatuntidf.zig").__floatuntidf, linkage);
+ @export("__floatuntisf", @import("compiler_rt/floatuntisf.zig").__floatuntisf, linkage);
+
+ @export("__extenddftf2", @import("compiler_rt/extendXfYf2.zig").__extenddftf2, linkage);
+ @export("__extendsftf2", @import("compiler_rt/extendXfYf2.zig").__extendsftf2, linkage);
+ @export("__extendhfsf2", @import("compiler_rt/extendXfYf2.zig").__extendhfsf2, linkage);
+
+ @export("__truncsfhf2", @import("compiler_rt/truncXfYf2.zig").__truncsfhf2, linkage);
+ @export("__truncdfhf2", @import("compiler_rt/truncXfYf2.zig").__truncdfhf2, linkage);
+ @export("__trunctfdf2", @import("compiler_rt/truncXfYf2.zig").__trunctfdf2, linkage);
+ @export("__trunctfsf2", @import("compiler_rt/truncXfYf2.zig").__trunctfsf2, linkage);
+
+ @export("__fixunssfsi", @import("compiler_rt/fixunssfsi.zig").__fixunssfsi, linkage);
+ @export("__fixunssfdi", @import("compiler_rt/fixunssfdi.zig").__fixunssfdi, linkage);
+ @export("__fixunssfti", @import("compiler_rt/fixunssfti.zig").__fixunssfti, linkage);
+
+ @export("__fixunsdfsi", @import("compiler_rt/fixunsdfsi.zig").__fixunsdfsi, linkage);
+ @export("__fixunsdfdi", @import("compiler_rt/fixunsdfdi.zig").__fixunsdfdi, linkage);
+ @export("__fixunsdfti", @import("compiler_rt/fixunsdfti.zig").__fixunsdfti, linkage);
+
+ @export("__fixunstfsi", @import("compiler_rt/fixunstfsi.zig").__fixunstfsi, linkage);
+ @export("__fixunstfdi", @import("compiler_rt/fixunstfdi.zig").__fixunstfdi, linkage);
+ @export("__fixunstfti", @import("compiler_rt/fixunstfti.zig").__fixunstfti, linkage);
+
+ @export("__fixdfdi", @import("compiler_rt/fixdfdi.zig").__fixdfdi, linkage);
+ @export("__fixdfsi", @import("compiler_rt/fixdfsi.zig").__fixdfsi, linkage);
+ @export("__fixdfti", @import("compiler_rt/fixdfti.zig").__fixdfti, linkage);
+ @export("__fixsfdi", @import("compiler_rt/fixsfdi.zig").__fixsfdi, linkage);
+ @export("__fixsfsi", @import("compiler_rt/fixsfsi.zig").__fixsfsi, linkage);
+ @export("__fixsfti", @import("compiler_rt/fixsfti.zig").__fixsfti, linkage);
+ @export("__fixtfdi", @import("compiler_rt/fixtfdi.zig").__fixtfdi, linkage);
+ @export("__fixtfsi", @import("compiler_rt/fixtfsi.zig").__fixtfsi, linkage);
+ @export("__fixtfti", @import("compiler_rt/fixtfti.zig").__fixtfti, linkage);
+
+ @export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage);
+
+ @export("__udivsi3", __udivsi3, linkage);
+ @export("__udivdi3", __udivdi3, linkage);
+ @export("__umoddi3", __umoddi3, linkage);
+ @export("__udivmodsi4", __udivmodsi4, linkage);
+
+ if (is_arm_arch and !is_arm_64) {
+ @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
+ @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage);
+ @export("__aeabi_uidiv", __udivsi3, linkage);
+ }
+ if (builtin.os == builtin.Os.windows) {
+ switch (builtin.arch) {
+ builtin.Arch.i386 => {
+ if (!builtin.link_libc) {
+ @export("_chkstk", _chkstk, strong_linkage);
+ @export("__chkstk_ms", __chkstk_ms, linkage);
+ }
+ @export("_aulldiv", @import("compiler_rt/aulldiv.zig")._aulldiv, strong_linkage);
+ @export("_aullrem", @import("compiler_rt/aullrem.zig")._aullrem, strong_linkage);
+ },
+ builtin.Arch.x86_64 => {
+ if (!builtin.link_libc) {
+ @export("__chkstk", __chkstk, strong_linkage);
+ @export("___chkstk_ms", ___chkstk_ms, linkage);
+ }
+ @export("__divti3", @import("compiler_rt/divti3.zig").__divti3_windows_x86_64, linkage);
+ @export("__multi3", @import("compiler_rt/multi3.zig").__multi3_windows_x86_64, linkage);
+ @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4_windows_x86_64, linkage);
+ @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3_windows_x86_64, linkage);
+ @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
+ @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3_windows_x86_64, linkage);
+ },
+ else => {},
+ }
+ } else {
+ @export("__divti3", @import("compiler_rt/divti3.zig").__divti3, linkage);
+ @export("__multi3", @import("compiler_rt/multi3.zig").__multi3, linkage);
+ @export("__muloti4", @import("compiler_rt/muloti4.zig").__muloti4, linkage);
+ @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3, linkage);
+ @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4, linkage);
+ @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3, linkage);
+ }
+}
+
+const std = @import("std");
+const assert = std.debug.assert;
+const testing = std.testing;
+
+const __udivmoddi4 = @import("compiler_rt/udivmoddi4.zig").__udivmoddi4;
+
+// Avoid dragging in the runtime safety mechanisms into this .o file,
+// unless we're trying to test this file.
+pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
+ @setCold(true);
+ if (is_test) {
+ std.debug.panic("{}", msg);
+ } else {
+ unreachable;
+ }
+}
+
+pub fn setXmm0(comptime T: type, value: T) void {
+ comptime assert(builtin.arch == builtin.Arch.x86_64);
+ const aligned_value: T align(16) = value;
+ asm volatile (
+ \\movaps (%[ptr]), %%xmm0
+ :
+ : [ptr] "r" (&aligned_value)
+ : "xmm0"
+ );
+}
+
+extern fn __udivdi3(a: u64, b: u64) u64 {
+ @setRuntimeSafety(is_test);
+ return __udivmoddi4(a, b, null);
+}
+
+extern fn __umoddi3(a: u64, b: u64) u64 {
+ @setRuntimeSafety(is_test);
+
+ var r: u64 = undefined;
+ _ = __udivmoddi4(a, b, &r);
+ return r;
+}
+
+const AeabiUlDivModResult = extern struct {
+ quot: u64,
+ rem: u64,
+};
+extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult {
+ @setRuntimeSafety(is_test);
+ var result: AeabiUlDivModResult = undefined;
+ result.quot = __udivmoddi4(numerator, denominator, &result.rem);
+ return result;
+}
+
+const is_arm_64 = switch (builtin.arch) {
+ builtin.Arch.aarch64,
+ builtin.Arch.aarch64_be,
+ => true,
+ else => false,
+};
+
+const is_arm_arch = switch (builtin.arch) {
+ builtin.Arch.arm,
+ builtin.Arch.armeb,
+ builtin.Arch.aarch64,
+ builtin.Arch.aarch64_be,
+ builtin.Arch.thumb,
+ builtin.Arch.thumbeb,
+ => true,
+ else => false,
+};
+
+nakedcc fn __aeabi_uidivmod() void {
+ @setRuntimeSafety(false);
+ asm volatile (
+ \\ push { lr }
+ \\ sub sp, sp, #4
+ \\ mov r2, sp
+ \\ bl __udivmodsi4
+ \\ ldr r1, [sp]
+ \\ add sp, sp, #4
+ \\ pop { pc }
+ :
+ :
+ : "r2", "r1"
+ );
+}
+
+// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
+// then decrement %esp by %eax. Preserves all registers except %esp and flags.
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+nakedcc fn _chkstk() align(4) void {
+ @setRuntimeSafety(false);
+
+ asm volatile (
+ \\ push %%ecx
+ \\ push %%eax
+ \\ cmp $0x1000,%%eax
+ \\ lea 12(%%esp),%%ecx
+ \\ jb 1f
+ \\ 2:
+ \\ sub $0x1000,%%ecx
+ \\ test %%ecx,(%%ecx)
+ \\ sub $0x1000,%%eax
+ \\ cmp $0x1000,%%eax
+ \\ ja 2b
+ \\ 1:
+ \\ sub %%eax,%%ecx
+ \\ test %%ecx,(%%ecx)
+ \\ pop %%eax
+ \\ pop %%ecx
+ \\ ret
+ );
+}
+
+nakedcc fn __chkstk() align(4) void {
+ @setRuntimeSafety(false);
+
+ asm volatile (
+ \\ push %%rcx
+ \\ push %%rax
+ \\ cmp $0x1000,%%rax
+ \\ lea 24(%%rsp),%%rcx
+ \\ jb 1f
+ \\2:
+ \\ sub $0x1000,%%rcx
+ \\ test %%rcx,(%%rcx)
+ \\ sub $0x1000,%%rax
+ \\ cmp $0x1000,%%rax
+ \\ ja 2b
+ \\1:
+ \\ sub %%rax,%%rcx
+ \\ test %%rcx,(%%rcx)
+ \\ pop %%rax
+ \\ pop %%rcx
+ \\ ret
+ );
+}
+
+// _chkstk routine
+// This routine is windows specific
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+nakedcc fn __chkstk_ms() align(4) void {
+ @setRuntimeSafety(false);
+
+ asm volatile (
+ \\ push %%ecx
+ \\ push %%eax
+ \\ cmp $0x1000,%%eax
+ \\ lea 12(%%esp),%%ecx
+ \\ jb 1f
+ \\ 2:
+ \\ sub $0x1000,%%ecx
+ \\ test %%ecx,(%%ecx)
+ \\ sub $0x1000,%%eax
+ \\ cmp $0x1000,%%eax
+ \\ ja 2b
+ \\ 1:
+ \\ sub %%eax,%%ecx
+ \\ test %%ecx,(%%ecx)
+ \\ pop %%eax
+ \\ pop %%ecx
+ \\ ret
+ );
+}
+
+nakedcc fn ___chkstk_ms() align(4) void {
+ @setRuntimeSafety(false);
+
+ asm volatile (
+ \\ push %%rcx
+ \\ push %%rax
+ \\ cmp $0x1000,%%rax
+ \\ lea 24(%%rsp),%%rcx
+ \\ jb 1f
+ \\2:
+ \\ sub $0x1000,%%rcx
+ \\ test %%rcx,(%%rcx)
+ \\ sub $0x1000,%%rax
+ \\ cmp $0x1000,%%rax
+ \\ ja 2b
+ \\1:
+ \\ sub %%rax,%%rcx
+ \\ test %%rcx,(%%rcx)
+ \\ pop %%rax
+ \\ pop %%rcx
+ \\ ret
+ );
+}
+
+extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 {
+ @setRuntimeSafety(is_test);
+
+ const d = __udivsi3(a, b);
+ rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b)));
+ return d;
+}
+
+extern fn __udivsi3(n: u32, d: u32) u32 {
+ @setRuntimeSafety(is_test);
+
+ const n_uword_bits: c_uint = u32.bit_count;
+ // special cases
+ if (d == 0) return 0; // ?!
+ if (n == 0) return 0;
+ var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
+ // 0 <= sr <= n_uword_bits - 1 or sr large
+ if (sr > n_uword_bits - 1) {
+ // d > r
+ return 0;
+ }
+ if (sr == n_uword_bits - 1) {
+ // d == 1
+ return n;
+ }
+ sr += 1;
+ // 1 <= sr <= n_uword_bits - 1
+ // Not a special case
+ var q: u32 = n << @intCast(u5, n_uword_bits - sr);
+ var r: u32 = n >> @intCast(u5, sr);
+ var carry: u32 = 0;
+ while (sr > 0) : (sr -= 1) {
+ // r:q = ((r:q) << 1) | carry
+ r = (r << 1) | (q >> @intCast(u5, n_uword_bits - 1));
+ q = (q << 1) | carry;
+ // carry = 0;
+ // if (r.all >= d.all)
+ // {
+ // r.all -= d.all;
+ // carry = 1;
+ // }
+ const s = @intCast(i32, d -% r -% 1) >> @intCast(u5, n_uword_bits - 1);
+ carry = @intCast(u32, s & 1);
+ r -= d & @bitCast(u32, s);
+ }
+ q = (q << 1) | carry;
+ return q;
+}
+
+test "test_umoddi3" {
+ test_one_umoddi3(0, 1, 0);
+ test_one_umoddi3(2, 1, 0);
+ test_one_umoddi3(0x8000000000000000, 1, 0x0);
+ test_one_umoddi3(0x8000000000000000, 2, 0x0);
+ test_one_umoddi3(0xFFFFFFFFFFFFFFFF, 2, 0x1);
+}
+
+fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
+ const r = __umoddi3(a, b);
+ testing.expect(r == expected_r);
+}
+
+test "test_udivsi3" {
+ const cases = [][3]u32{
+ []u32{
+ 0x00000000,
+ 0x00000001,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x00000002,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x00000003,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x00000010,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x0747AE14,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x00000001,
+ 0x00000001,
+ },
+ []u32{
+ 0x00000001,
+ 0x00000002,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x00000003,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x00000010,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x0747AE14,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000001,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x00000001,
+ 0x00000002,
+ },
+ []u32{
+ 0x00000002,
+ 0x00000002,
+ 0x00000001,
+ },
+ []u32{
+ 0x00000002,
+ 0x00000003,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x00000010,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x0747AE14,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000002,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0x00000001,
+ 0x00000003,
+ },
+ []u32{
+ 0x00000003,
+ 0x00000002,
+ 0x00000001,
+ },
+ []u32{
+ 0x00000003,
+ 0x00000003,
+ 0x00000001,
+ },
+ []u32{
+ 0x00000003,
+ 0x00000010,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0x0747AE14,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000003,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0x00000001,
+ 0x00000010,
+ },
+ []u32{
+ 0x00000010,
+ 0x00000002,
+ 0x00000008,
+ },
+ []u32{
+ 0x00000010,
+ 0x00000003,
+ 0x00000005,
+ },
+ []u32{
+ 0x00000010,
+ 0x00000010,
+ 0x00000001,
+ },
+ []u32{
+ 0x00000010,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0x0747AE14,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x00000010,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x078644FA,
+ 0x00000001,
+ 0x078644FA,
+ },
+ []u32{
+ 0x078644FA,
+ 0x00000002,
+ 0x03C3227D,
+ },
+ []u32{
+ 0x078644FA,
+ 0x00000003,
+ 0x028216FE,
+ },
+ []u32{
+ 0x078644FA,
+ 0x00000010,
+ 0x0078644F,
+ },
+ []u32{
+ 0x078644FA,
+ 0x078644FA,
+ 0x00000001,
+ },
+ []u32{
+ 0x078644FA,
+ 0x0747AE14,
+ 0x00000001,
+ },
+ []u32{
+ 0x078644FA,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x078644FA,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x078644FA,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x078644FA,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x078644FA,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x00000001,
+ 0x0747AE14,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x00000002,
+ 0x03A3D70A,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x00000003,
+ 0x026D3A06,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x00000010,
+ 0x00747AE1,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x078644FA,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x0747AE14,
+ 0x00000001,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x7FFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x0747AE14,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x00000001,
+ 0x7FFFFFFF,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x00000002,
+ 0x3FFFFFFF,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x00000003,
+ 0x2AAAAAAA,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x00000010,
+ 0x07FFFFFF,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x078644FA,
+ 0x00000011,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x0747AE14,
+ 0x00000011,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x7FFFFFFF,
+ 0x00000001,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0x80000000,
+ 0x00000000,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x7FFFFFFF,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0x80000000,
+ 0x00000001,
+ 0x80000000,
+ },
+ []u32{
+ 0x80000000,
+ 0x00000002,
+ 0x40000000,
+ },
+ []u32{
+ 0x80000000,
+ 0x00000003,
+ 0x2AAAAAAA,
+ },
+ []u32{
+ 0x80000000,
+ 0x00000010,
+ 0x08000000,
+ },
+ []u32{
+ 0x80000000,
+ 0x078644FA,
+ 0x00000011,
+ },
+ []u32{
+ 0x80000000,
+ 0x0747AE14,
+ 0x00000011,
+ },
+ []u32{
+ 0x80000000,
+ 0x7FFFFFFF,
+ 0x00000001,
+ },
+ []u32{
+ 0x80000000,
+ 0x80000000,
+ 0x00000001,
+ },
+ []u32{
+ 0x80000000,
+ 0xFFFFFFFD,
+ 0x00000000,
+ },
+ []u32{
+ 0x80000000,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0x80000000,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x00000001,
+ 0xFFFFFFFD,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x00000002,
+ 0x7FFFFFFE,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x00000003,
+ 0x55555554,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x00000010,
+ 0x0FFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x078644FA,
+ 0x00000022,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x0747AE14,
+ 0x00000023,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x7FFFFFFF,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0x80000000,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0xFFFFFFFD,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0xFFFFFFFE,
+ 0x00000000,
+ },
+ []u32{
+ 0xFFFFFFFD,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x00000001,
+ 0xFFFFFFFE,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x00000002,
+ 0x7FFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x00000003,
+ 0x55555554,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x00000010,
+ 0x0FFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x078644FA,
+ 0x00000022,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x0747AE14,
+ 0x00000023,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x7FFFFFFF,
+ 0x00000002,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0x80000000,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0xFFFFFFFD,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0xFFFFFFFE,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFE,
+ 0xFFFFFFFF,
+ 0x00000000,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x00000001,
+ 0xFFFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x00000002,
+ 0x7FFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x00000003,
+ 0x55555555,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x00000010,
+ 0x0FFFFFFF,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x078644FA,
+ 0x00000022,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x0747AE14,
+ 0x00000023,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x7FFFFFFF,
+ 0x00000002,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0x80000000,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0xFFFFFFFD,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0xFFFFFFFE,
+ 0x00000001,
+ },
+ []u32{
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0x00000001,
+ },
+ };
+
+ for (cases) |case| {
+ test_one_udivsi3(case[0], case[1], case[2]);
+ }
+}
+
+fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void {
+ const q: u32 = __udivsi3(a, b);
+ testing.expect(q == expected_q);
+}
diff --git a/std/special/compiler_rt/addXf3.zig b/std/special/compiler_rt/addXf3.zig
index 09413b23287cf4e16e6fc37c977a62636e7c67f7..c7e80e4e713a6eac3496ea0104bb6869a974e948 100644
--- a/std/special/compiler_rt/addXf3.zig
+++ b/std/special/compiler_rt/addXf3.zig
@@ -4,7 +4,7 @@
const std = @import("std");
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __addtf3(a: f128, b: f128) f128 {
return addXf3(f128, a, b);
diff --git a/std/special/compiler_rt/divti3.zig b/std/special/compiler_rt/divti3.zig
index 712cccba8234649bc2b76471bf0d990ce8b7eaf3..e89a1ada5c82e6b566ae5f67f078a06c0d27f77c 100644
--- a/std/special/compiler_rt/divti3.zig
+++ b/std/special/compiler_rt/divti3.zig
@@ -1,6 +1,6 @@
const udivmod = @import("udivmod.zig").udivmod;
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __divti3(a: i128, b: i128) i128 {
@setRuntimeSafety(builtin.is_test);
diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig
deleted file mode 100644
index 7657ce61186ac5fdbf7437f0142d1b50bdc711cc..0000000000000000000000000000000000000000
--- a/std/special/compiler_rt/index.zig
+++ /dev/null
@@ -1,1050 +0,0 @@
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-
-comptime {
- const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
- const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong;
-
- @export("__letf2", @import("comparetf2.zig").__letf2, linkage);
- @export("__getf2", @import("comparetf2.zig").__getf2, linkage);
-
- if (!is_test) {
- // only create these aliases when not testing
- @export("__cmptf2", @import("comparetf2.zig").__letf2, linkage);
- @export("__eqtf2", @import("comparetf2.zig").__letf2, linkage);
- @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
- @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
- @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);
- @export("__gnu_h2f_ieee", @import("extendXfYf2.zig").__extendhfsf2, linkage);
- @export("__gnu_f2h_ieee", @import("truncXfYf2.zig").__truncsfhf2, linkage);
- }
-
- @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
-
- @export("__addtf3", @import("addXf3.zig").__addtf3, linkage);
- @export("__subtf3", @import("addXf3.zig").__subtf3, linkage);
-
- @export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
- @export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
- @export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
-
- @export("__floatunditf", @import("floatunditf.zig").__floatunditf, linkage);
- @export("__floatunsitf", @import("floatunsitf.zig").__floatunsitf, linkage);
-
- @export("__floatuntitf", @import("floatuntitf.zig").__floatuntitf, linkage);
- @export("__floatuntidf", @import("floatuntidf.zig").__floatuntidf, linkage);
- @export("__floatuntisf", @import("floatuntisf.zig").__floatuntisf, linkage);
-
- @export("__extenddftf2", @import("extendXfYf2.zig").__extenddftf2, linkage);
- @export("__extendsftf2", @import("extendXfYf2.zig").__extendsftf2, linkage);
- @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
-
- @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
- @export("__truncdfhf2", @import("truncXfYf2.zig").__truncdfhf2, linkage);
- @export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
- @export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
-
- @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
- @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
- @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage);
-
- @export("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage);
- @export("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage);
- @export("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage);
-
- @export("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage);
- @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage);
- @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage);
-
- @export("__fixdfdi", @import("fixdfdi.zig").__fixdfdi, linkage);
- @export("__fixdfsi", @import("fixdfsi.zig").__fixdfsi, linkage);
- @export("__fixdfti", @import("fixdfti.zig").__fixdfti, linkage);
- @export("__fixsfdi", @import("fixsfdi.zig").__fixsfdi, linkage);
- @export("__fixsfsi", @import("fixsfsi.zig").__fixsfsi, linkage);
- @export("__fixsfti", @import("fixsfti.zig").__fixsfti, linkage);
- @export("__fixtfdi", @import("fixtfdi.zig").__fixtfdi, linkage);
- @export("__fixtfsi", @import("fixtfsi.zig").__fixtfsi, linkage);
- @export("__fixtfti", @import("fixtfti.zig").__fixtfti, linkage);
-
- @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage);
-
- @export("__udivsi3", __udivsi3, linkage);
- @export("__udivdi3", __udivdi3, linkage);
- @export("__umoddi3", __umoddi3, linkage);
- @export("__udivmodsi4", __udivmodsi4, linkage);
-
- if (is_arm_arch and !is_arm_64) {
- @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
- @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage);
- @export("__aeabi_uidiv", __udivsi3, linkage);
- }
- if (builtin.os == builtin.Os.windows) {
- switch (builtin.arch) {
- builtin.Arch.i386 => {
- if (!builtin.link_libc) {
- @export("_chkstk", _chkstk, strong_linkage);
- @export("__chkstk_ms", __chkstk_ms, linkage);
- }
- @export("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage);
- @export("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage);
- },
- builtin.Arch.x86_64 => {
- if (!builtin.link_libc) {
- @export("__chkstk", __chkstk, strong_linkage);
- @export("___chkstk_ms", ___chkstk_ms, linkage);
- }
- @export("__divti3", @import("divti3.zig").__divti3_windows_x86_64, linkage);
- @export("__multi3", @import("multi3.zig").__multi3_windows_x86_64, linkage);
- @export("__muloti4", @import("muloti4.zig").__muloti4_windows_x86_64, linkage);
- @export("__udivti3", @import("udivti3.zig").__udivti3_windows_x86_64, linkage);
- @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4_windows_x86_64, linkage);
- @export("__umodti3", @import("umodti3.zig").__umodti3_windows_x86_64, linkage);
- },
- else => {},
- }
- } else {
- @export("__divti3", @import("divti3.zig").__divti3, linkage);
- @export("__multi3", @import("multi3.zig").__multi3, linkage);
- @export("__muloti4", @import("muloti4.zig").__muloti4, linkage);
- @export("__udivti3", @import("udivti3.zig").__udivti3, linkage);
- @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage);
- @export("__umodti3", @import("umodti3.zig").__umodti3, linkage);
- }
-}
-
-const std = @import("std");
-const assert = std.debug.assert;
-const testing = std.testing;
-
-const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
-
-// Avoid dragging in the runtime safety mechanisms into this .o file,
-// unless we're trying to test this file.
-pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
- @setCold(true);
- if (is_test) {
- std.debug.panic("{}", msg);
- } else {
- unreachable;
- }
-}
-
-pub fn setXmm0(comptime T: type, value: T) void {
- comptime assert(builtin.arch == builtin.Arch.x86_64);
- const aligned_value: T align(16) = value;
- asm volatile (
- \\movaps (%[ptr]), %%xmm0
- :
- : [ptr] "r" (&aligned_value)
- : "xmm0"
- );
-}
-
-extern fn __udivdi3(a: u64, b: u64) u64 {
- @setRuntimeSafety(is_test);
- return __udivmoddi4(a, b, null);
-}
-
-extern fn __umoddi3(a: u64, b: u64) u64 {
- @setRuntimeSafety(is_test);
-
- var r: u64 = undefined;
- _ = __udivmoddi4(a, b, &r);
- return r;
-}
-
-const AeabiUlDivModResult = extern struct {
- quot: u64,
- rem: u64,
-};
-extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult {
- @setRuntimeSafety(is_test);
- var result: AeabiUlDivModResult = undefined;
- result.quot = __udivmoddi4(numerator, denominator, &result.rem);
- return result;
-}
-
-const is_arm_64 = switch (builtin.arch) {
- builtin.Arch.aarch64v8_3a,
- builtin.Arch.aarch64v8_2a,
- builtin.Arch.aarch64v8_1a,
- builtin.Arch.aarch64v8,
- builtin.Arch.aarch64v8r,
- builtin.Arch.aarch64v8m_baseline,
- builtin.Arch.aarch64v8m_mainline,
- builtin.Arch.aarch64_bev8_3a,
- builtin.Arch.aarch64_bev8_2a,
- builtin.Arch.aarch64_bev8_1a,
- builtin.Arch.aarch64_bev8,
- builtin.Arch.aarch64_bev8r,
- builtin.Arch.aarch64_bev8m_baseline,
- builtin.Arch.aarch64_bev8m_mainline,
- => true,
- else => false,
-};
-
-const is_arm_arch = switch (builtin.arch) {
- builtin.Arch.arm,
- builtin.Arch.armeb,
- builtin.Arch.aarch64,
- builtin.Arch.aarch64_be,
- builtin.Arch.thumb,
- builtin.Arch.thumbeb,
- => true,
- else => false,
-};
-
-nakedcc fn __aeabi_uidivmod() void {
- @setRuntimeSafety(false);
- asm volatile (
- \\ push { lr }
- \\ sub sp, sp, #4
- \\ mov r2, sp
- \\ bl __udivmodsi4
- \\ ldr r1, [sp]
- \\ add sp, sp, #4
- \\ pop { pc }
- :
- :
- : "r2", "r1"
- );
-}
-
-// _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments,
-// then decrement %esp by %eax. Preserves all registers except %esp and flags.
-// This routine is windows specific
-// http://msdn.microsoft.com/en-us/library/ms648426.aspx
-nakedcc fn _chkstk() align(4) void {
- @setRuntimeSafety(false);
-
- asm volatile (
- \\ push %%ecx
- \\ push %%eax
- \\ cmp $0x1000,%%eax
- \\ lea 12(%%esp),%%ecx
- \\ jb 1f
- \\ 2:
- \\ sub $0x1000,%%ecx
- \\ test %%ecx,(%%ecx)
- \\ sub $0x1000,%%eax
- \\ cmp $0x1000,%%eax
- \\ ja 2b
- \\ 1:
- \\ sub %%eax,%%ecx
- \\ test %%ecx,(%%ecx)
- \\ pop %%eax
- \\ pop %%ecx
- \\ ret
- );
-}
-
-nakedcc fn __chkstk() align(4) void {
- @setRuntimeSafety(false);
-
- asm volatile (
- \\ push %%rcx
- \\ push %%rax
- \\ cmp $0x1000,%%rax
- \\ lea 24(%%rsp),%%rcx
- \\ jb 1f
- \\2:
- \\ sub $0x1000,%%rcx
- \\ test %%rcx,(%%rcx)
- \\ sub $0x1000,%%rax
- \\ cmp $0x1000,%%rax
- \\ ja 2b
- \\1:
- \\ sub %%rax,%%rcx
- \\ test %%rcx,(%%rcx)
- \\ pop %%rax
- \\ pop %%rcx
- \\ ret
- );
-}
-
-// _chkstk routine
-// This routine is windows specific
-// http://msdn.microsoft.com/en-us/library/ms648426.aspx
-nakedcc fn __chkstk_ms() align(4) void {
- @setRuntimeSafety(false);
-
- asm volatile (
- \\ push %%ecx
- \\ push %%eax
- \\ cmp $0x1000,%%eax
- \\ lea 12(%%esp),%%ecx
- \\ jb 1f
- \\ 2:
- \\ sub $0x1000,%%ecx
- \\ test %%ecx,(%%ecx)
- \\ sub $0x1000,%%eax
- \\ cmp $0x1000,%%eax
- \\ ja 2b
- \\ 1:
- \\ sub %%eax,%%ecx
- \\ test %%ecx,(%%ecx)
- \\ pop %%eax
- \\ pop %%ecx
- \\ ret
- );
-}
-
-nakedcc fn ___chkstk_ms() align(4) void {
- @setRuntimeSafety(false);
-
- asm volatile (
- \\ push %%rcx
- \\ push %%rax
- \\ cmp $0x1000,%%rax
- \\ lea 24(%%rsp),%%rcx
- \\ jb 1f
- \\2:
- \\ sub $0x1000,%%rcx
- \\ test %%rcx,(%%rcx)
- \\ sub $0x1000,%%rax
- \\ cmp $0x1000,%%rax
- \\ ja 2b
- \\1:
- \\ sub %%rax,%%rcx
- \\ test %%rcx,(%%rcx)
- \\ pop %%rax
- \\ pop %%rcx
- \\ ret
- );
-}
-
-extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 {
- @setRuntimeSafety(is_test);
-
- const d = __udivsi3(a, b);
- rem.* = @bitCast(u32, @bitCast(i32, a) -% (@bitCast(i32, d) * @bitCast(i32, b)));
- return d;
-}
-
-extern fn __udivsi3(n: u32, d: u32) u32 {
- @setRuntimeSafety(is_test);
-
- const n_uword_bits: c_uint = u32.bit_count;
- // special cases
- if (d == 0) return 0; // ?!
- if (n == 0) return 0;
- var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n)));
- // 0 <= sr <= n_uword_bits - 1 or sr large
- if (sr > n_uword_bits - 1) {
- // d > r
- return 0;
- }
- if (sr == n_uword_bits - 1) {
- // d == 1
- return n;
- }
- sr += 1;
- // 1 <= sr <= n_uword_bits - 1
- // Not a special case
- var q: u32 = n << @intCast(u5, n_uword_bits - sr);
- var r: u32 = n >> @intCast(u5, sr);
- var carry: u32 = 0;
- while (sr > 0) : (sr -= 1) {
- // r:q = ((r:q) << 1) | carry
- r = (r << 1) | (q >> @intCast(u5, n_uword_bits - 1));
- q = (q << 1) | carry;
- // carry = 0;
- // if (r.all >= d.all)
- // {
- // r.all -= d.all;
- // carry = 1;
- // }
- const s = @intCast(i32, d -% r -% 1) >> @intCast(u5, n_uword_bits - 1);
- carry = @intCast(u32, s & 1);
- r -= d & @bitCast(u32, s);
- }
- q = (q << 1) | carry;
- return q;
-}
-
-test "test_umoddi3" {
- test_one_umoddi3(0, 1, 0);
- test_one_umoddi3(2, 1, 0);
- test_one_umoddi3(0x8000000000000000, 1, 0x0);
- test_one_umoddi3(0x8000000000000000, 2, 0x0);
- test_one_umoddi3(0xFFFFFFFFFFFFFFFF, 2, 0x1);
-}
-
-fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void {
- const r = __umoddi3(a, b);
- testing.expect(r == expected_r);
-}
-
-test "test_udivsi3" {
- const cases = [][3]u32{
- []u32{
- 0x00000000,
- 0x00000001,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x00000002,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x00000003,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x00000010,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x0747AE14,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x00000000,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x00000001,
- 0x00000001,
- },
- []u32{
- 0x00000001,
- 0x00000002,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x00000003,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x00000010,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x0747AE14,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x00000001,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x00000001,
- 0x00000002,
- },
- []u32{
- 0x00000002,
- 0x00000002,
- 0x00000001,
- },
- []u32{
- 0x00000002,
- 0x00000003,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x00000010,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x0747AE14,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x00000002,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0x00000001,
- 0x00000003,
- },
- []u32{
- 0x00000003,
- 0x00000002,
- 0x00000001,
- },
- []u32{
- 0x00000003,
- 0x00000003,
- 0x00000001,
- },
- []u32{
- 0x00000003,
- 0x00000010,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0x0747AE14,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x00000003,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0x00000001,
- 0x00000010,
- },
- []u32{
- 0x00000010,
- 0x00000002,
- 0x00000008,
- },
- []u32{
- 0x00000010,
- 0x00000003,
- 0x00000005,
- },
- []u32{
- 0x00000010,
- 0x00000010,
- 0x00000001,
- },
- []u32{
- 0x00000010,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0x0747AE14,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x00000010,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x078644FA,
- 0x00000001,
- 0x078644FA,
- },
- []u32{
- 0x078644FA,
- 0x00000002,
- 0x03C3227D,
- },
- []u32{
- 0x078644FA,
- 0x00000003,
- 0x028216FE,
- },
- []u32{
- 0x078644FA,
- 0x00000010,
- 0x0078644F,
- },
- []u32{
- 0x078644FA,
- 0x078644FA,
- 0x00000001,
- },
- []u32{
- 0x078644FA,
- 0x0747AE14,
- 0x00000001,
- },
- []u32{
- 0x078644FA,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x078644FA,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x078644FA,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x078644FA,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x078644FA,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0x00000001,
- 0x0747AE14,
- },
- []u32{
- 0x0747AE14,
- 0x00000002,
- 0x03A3D70A,
- },
- []u32{
- 0x0747AE14,
- 0x00000003,
- 0x026D3A06,
- },
- []u32{
- 0x0747AE14,
- 0x00000010,
- 0x00747AE1,
- },
- []u32{
- 0x0747AE14,
- 0x078644FA,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0x0747AE14,
- 0x00000001,
- },
- []u32{
- 0x0747AE14,
- 0x7FFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x0747AE14,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x7FFFFFFF,
- 0x00000001,
- 0x7FFFFFFF,
- },
- []u32{
- 0x7FFFFFFF,
- 0x00000002,
- 0x3FFFFFFF,
- },
- []u32{
- 0x7FFFFFFF,
- 0x00000003,
- 0x2AAAAAAA,
- },
- []u32{
- 0x7FFFFFFF,
- 0x00000010,
- 0x07FFFFFF,
- },
- []u32{
- 0x7FFFFFFF,
- 0x078644FA,
- 0x00000011,
- },
- []u32{
- 0x7FFFFFFF,
- 0x0747AE14,
- 0x00000011,
- },
- []u32{
- 0x7FFFFFFF,
- 0x7FFFFFFF,
- 0x00000001,
- },
- []u32{
- 0x7FFFFFFF,
- 0x80000000,
- 0x00000000,
- },
- []u32{
- 0x7FFFFFFF,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x7FFFFFFF,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x7FFFFFFF,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0x80000000,
- 0x00000001,
- 0x80000000,
- },
- []u32{
- 0x80000000,
- 0x00000002,
- 0x40000000,
- },
- []u32{
- 0x80000000,
- 0x00000003,
- 0x2AAAAAAA,
- },
- []u32{
- 0x80000000,
- 0x00000010,
- 0x08000000,
- },
- []u32{
- 0x80000000,
- 0x078644FA,
- 0x00000011,
- },
- []u32{
- 0x80000000,
- 0x0747AE14,
- 0x00000011,
- },
- []u32{
- 0x80000000,
- 0x7FFFFFFF,
- 0x00000001,
- },
- []u32{
- 0x80000000,
- 0x80000000,
- 0x00000001,
- },
- []u32{
- 0x80000000,
- 0xFFFFFFFD,
- 0x00000000,
- },
- []u32{
- 0x80000000,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0x80000000,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0xFFFFFFFD,
- 0x00000001,
- 0xFFFFFFFD,
- },
- []u32{
- 0xFFFFFFFD,
- 0x00000002,
- 0x7FFFFFFE,
- },
- []u32{
- 0xFFFFFFFD,
- 0x00000003,
- 0x55555554,
- },
- []u32{
- 0xFFFFFFFD,
- 0x00000010,
- 0x0FFFFFFF,
- },
- []u32{
- 0xFFFFFFFD,
- 0x078644FA,
- 0x00000022,
- },
- []u32{
- 0xFFFFFFFD,
- 0x0747AE14,
- 0x00000023,
- },
- []u32{
- 0xFFFFFFFD,
- 0x7FFFFFFF,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFD,
- 0x80000000,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFD,
- 0xFFFFFFFD,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFD,
- 0xFFFFFFFE,
- 0x00000000,
- },
- []u32{
- 0xFFFFFFFD,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0xFFFFFFFE,
- 0x00000001,
- 0xFFFFFFFE,
- },
- []u32{
- 0xFFFFFFFE,
- 0x00000002,
- 0x7FFFFFFF,
- },
- []u32{
- 0xFFFFFFFE,
- 0x00000003,
- 0x55555554,
- },
- []u32{
- 0xFFFFFFFE,
- 0x00000010,
- 0x0FFFFFFF,
- },
- []u32{
- 0xFFFFFFFE,
- 0x078644FA,
- 0x00000022,
- },
- []u32{
- 0xFFFFFFFE,
- 0x0747AE14,
- 0x00000023,
- },
- []u32{
- 0xFFFFFFFE,
- 0x7FFFFFFF,
- 0x00000002,
- },
- []u32{
- 0xFFFFFFFE,
- 0x80000000,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFE,
- 0xFFFFFFFD,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFE,
- 0xFFFFFFFE,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFE,
- 0xFFFFFFFF,
- 0x00000000,
- },
- []u32{
- 0xFFFFFFFF,
- 0x00000001,
- 0xFFFFFFFF,
- },
- []u32{
- 0xFFFFFFFF,
- 0x00000002,
- 0x7FFFFFFF,
- },
- []u32{
- 0xFFFFFFFF,
- 0x00000003,
- 0x55555555,
- },
- []u32{
- 0xFFFFFFFF,
- 0x00000010,
- 0x0FFFFFFF,
- },
- []u32{
- 0xFFFFFFFF,
- 0x078644FA,
- 0x00000022,
- },
- []u32{
- 0xFFFFFFFF,
- 0x0747AE14,
- 0x00000023,
- },
- []u32{
- 0xFFFFFFFF,
- 0x7FFFFFFF,
- 0x00000002,
- },
- []u32{
- 0xFFFFFFFF,
- 0x80000000,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFF,
- 0xFFFFFFFD,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFF,
- 0xFFFFFFFE,
- 0x00000001,
- },
- []u32{
- 0xFFFFFFFF,
- 0xFFFFFFFF,
- 0x00000001,
- },
- };
-
- for (cases) |case| {
- test_one_udivsi3(case[0], case[1], case[2]);
- }
-}
-
-fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void {
- const q: u32 = __udivsi3(a, b);
- testing.expect(q == expected_q);
-}
diff --git a/std/special/compiler_rt/muloti4.zig b/std/special/compiler_rt/muloti4.zig
index 866077c80c3ccebbf351b7ff256462d2e04241fa..fd6855072b11c67e66c9cd0fd3fead725de29f53 100644
--- a/std/special/compiler_rt/muloti4.zig
+++ b/std/special/compiler_rt/muloti4.zig
@@ -1,6 +1,6 @@
const udivmod = @import("udivmod.zig").udivmod;
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 {
@setRuntimeSafety(builtin.is_test);
diff --git a/std/special/compiler_rt/multi3.zig b/std/special/compiler_rt/multi3.zig
index 1152a8bda010e536c467a1454a67f52e18efdb39..a0c84adaf4197ef88b7e56d674d020ea79c90085 100644
--- a/std/special/compiler_rt/multi3.zig
+++ b/std/special/compiler_rt/multi3.zig
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
// Ported from git@github.com:llvm-project/llvm-project-20170507.git
// ae684fad6d34858c014c94da69c15e7774a633c3
diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig
index 3fa596442f2793e01533059d3e2d70568c150596..6a037d3bae7751f0ca173bafa3704f7a86d4f3fb 100644
--- a/std/special/compiler_rt/udivmodti4.zig
+++ b/std/special/compiler_rt/udivmodti4.zig
@@ -1,6 +1,6 @@
const udivmod = @import("udivmod.zig").udivmod;
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) u128 {
@setRuntimeSafety(builtin.is_test);
diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig
index 9551e63a6f8e6a3bea085582759aab4290dc6fd6..12aca8b03623e5793ce6f736640dc9d49aa0a506 100644
--- a/std/special/compiler_rt/umodti3.zig
+++ b/std/special/compiler_rt/umodti3.zig
@@ -1,6 +1,6 @@
const udivmodti4 = @import("udivmodti4.zig");
const builtin = @import("builtin");
-const compiler_rt = @import("index.zig");
+const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __umodti3(a: u128, b: u128) u128 {
@setRuntimeSafety(builtin.is_test);
diff --git a/std/special/panic.zig b/std/special/panic.zig
index bd3ad971e0cb634422b56ce3b396aa2fdbe719a4..7cb7143955f051529c49333ed576fc666f7e5d0f 100644
--- a/std/special/panic.zig
+++ b/std/special/panic.zig
@@ -18,7 +18,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
std.os.abort();
},
else => {
- const first_trace_addr = @ptrToInt(@returnAddress());
+ const first_trace_addr = @returnAddress();
std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
},
}
diff --git a/std/spinlock.zig b/std/spinlock.zig
index 75fdf9f6e1f67399607d62bd9bb4b2d316e78f4a..905460a2d0c6ec21e775d2256cb21276b0e218f9 100644
--- a/std/spinlock.zig
+++ b/std/spinlock.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const AtomicOrder = builtin.AtomicOrder;
const AtomicRmwOp = builtin.AtomicRmwOp;
diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig
index 16bcd7adafe49dffdd1c26c0c30a5c7b4ec6b67f..cfcaf036d392b2d891ea00b269b7019fb3d88284 100644
--- a/std/statically_initialized_mutex.zig
+++ b/std/statically_initialized_mutex.zig
@@ -1,4 +1,4 @@
-const std = @import("index.zig");
+const std = @import("std.zig");
const builtin = @import("builtin");
const AtomicOrder = builtin.AtomicOrder;
const AtomicRmwOp = builtin.AtomicRmwOp;
@@ -13,7 +13,7 @@ const windows = std.os.windows;
/// On Windows, this mutex allocates resources when it is
/// first used, and the resources cannot be freed.
/// On Linux, this is an alias of std.Mutex.
-pub const StaticallyInitializedMutex = switch(builtin.os) {
+pub const StaticallyInitializedMutex = switch (builtin.os) {
builtin.Os.linux => std.Mutex,
builtin.Os.windows => struct {
lock: windows.CRITICAL_SECTION,
@@ -28,7 +28,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
};
pub fn init() StaticallyInitializedMutex {
- return StaticallyInitializedMutex {
+ return StaticallyInitializedMutex{
.lock = undefined,
.init_once = windows.INIT_ONCE_STATIC_INIT,
};
@@ -54,7 +54,7 @@ pub const StaticallyInitializedMutex = switch(builtin.os) {
pub fn acquire(self: *StaticallyInitializedMutex) Held {
assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
windows.EnterCriticalSection(&self.lock);
- return Held { .mutex = self };
+ return Held{ .mutex = self };
}
},
else => std.Mutex,
@@ -89,10 +89,7 @@ test "std.StaticallyInitializedMutex" {
var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
var a = &fixed_buffer_allocator.allocator;
-
- var context = TestContext{
- .data = 0,
- };
+ var context = TestContext{ .data = 0 };
if (builtin.single_threaded) {
TestContext.worker(&context);
diff --git a/std/std.zig b/std/std.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4a81fc7c3569d74eb2a36f0206b656571308a800
--- /dev/null
+++ b/std/std.zig
@@ -0,0 +1,95 @@
+pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
+pub const ArrayList = @import("array_list.zig").ArrayList;
+pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;
+pub const BufMap = @import("buf_map.zig").BufMap;
+pub const BufSet = @import("buf_set.zig").BufSet;
+pub const Buffer = @import("buffer.zig").Buffer;
+pub const BufferOutStream = @import("io.zig").BufferOutStream;
+pub const DynLib = @import("dynamic_library.zig").DynLib;
+pub const HashMap = @import("hash_map.zig").HashMap;
+pub const LinkedList = @import("linked_list.zig").LinkedList;
+pub const Mutex = @import("mutex.zig").Mutex;
+pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
+pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
+pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
+pub const SpinLock = @import("spinlock.zig").SpinLock;
+
+pub const atomic = @import("atomic.zig");
+pub const base64 = @import("base64.zig");
+pub const build = @import("build.zig");
+pub const c = @import("c.zig");
+pub const coff = @import("coff.zig");
+pub const crypto = @import("crypto.zig");
+pub const cstr = @import("cstr.zig");
+pub const debug = @import("debug.zig");
+pub const dwarf = @import("dwarf.zig");
+pub const elf = @import("elf.zig");
+pub const empty_import = @import("empty.zig");
+pub const event = @import("event.zig");
+pub const fmt = @import("fmt.zig");
+pub const hash = @import("hash.zig");
+pub const hash_map = @import("hash_map.zig");
+pub const heap = @import("heap.zig");
+pub const io = @import("io.zig");
+pub const json = @import("json.zig");
+pub const lazyInit = @import("lazy_init.zig").lazyInit;
+pub const macho = @import("macho.zig");
+pub const math = @import("math.zig");
+pub const mem = @import("mem.zig");
+pub const meta = @import("meta.zig");
+pub const net = @import("net.zig");
+pub const os = @import("os.zig");
+pub const pdb = @import("pdb.zig");
+pub const rand = @import("rand.zig");
+pub const rb = @import("rb.zig");
+pub const sort = @import("sort.zig");
+pub const testing = @import("testing.zig");
+pub const unicode = @import("unicode.zig");
+pub const zig = @import("zig.zig");
+
+test "std" {
+ // run tests from these
+ _ = @import("array_list.zig");
+ _ = @import("atomic.zig");
+ _ = @import("buf_map.zig");
+ _ = @import("buf_set.zig");
+ _ = @import("buffer.zig");
+ _ = @import("hash_map.zig");
+ _ = @import("linked_list.zig");
+ _ = @import("mutex.zig");
+ _ = @import("statically_initialized_mutex.zig");
+ _ = @import("segmented_list.zig");
+ _ = @import("spinlock.zig");
+
+ _ = @import("base64.zig");
+ _ = @import("build.zig");
+ _ = @import("c.zig");
+ _ = @import("coff.zig");
+ _ = @import("crypto.zig");
+ _ = @import("cstr.zig");
+ _ = @import("debug.zig");
+ _ = @import("dwarf.zig");
+ _ = @import("dynamic_library.zig");
+ _ = @import("elf.zig");
+ _ = @import("empty.zig");
+ _ = @import("event.zig");
+ _ = @import("fmt.zig");
+ _ = @import("hash.zig");
+ _ = @import("heap.zig");
+ _ = @import("io.zig");
+ _ = @import("json.zig");
+ _ = @import("lazy_init.zig");
+ _ = @import("macho.zig");
+ _ = @import("math.zig");
+ _ = @import("mem.zig");
+ _ = @import("meta.zig");
+ _ = @import("net.zig");
+ _ = @import("os.zig");
+ _ = @import("pdb.zig");
+ _ = @import("priority_queue.zig");
+ _ = @import("rand.zig");
+ _ = @import("sort.zig");
+ _ = @import("testing.zig");
+ _ = @import("unicode.zig");
+ _ = @import("zig.zig");
+}
diff --git a/std/testing.zig b/std/testing.zig
index 2f14974481e6ea61c9e8bb6aec120d30dd849e4e..be414181f20c9e72f13dbbd151b3999525d44a5b 100644
--- a/std/testing.zig
+++ b/std/testing.zig
@@ -1,6 +1,6 @@
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
-const std = @import("index.zig");
+const std = @import("std.zig");
/// This function is intended to be used only in tests. It prints diagnostics to stderr
/// and then aborts when actual_error_union is not expected_error.
@@ -44,7 +44,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
TypeId.ComptimeFloat,
TypeId.ComptimeInt,
TypeId.Enum,
- TypeId.Namespace,
TypeId.Fn,
TypeId.Promise,
TypeId.Vector,
diff --git a/std/unicode.zig b/std/unicode.zig
index fccdf513b90527565b38a5f77e0132be6dd8a0fa..37a73d75004bd943a19fa8aaa7153308b185d3a0 100644
--- a/std/unicode.zig
+++ b/std/unicode.zig
@@ -1,4 +1,4 @@
-const std = @import("./index.zig");
+const std = @import("./std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
diff --git a/std/zig.zig b/std/zig.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2d4978a4aec8e3254b17a182c0ce16b43164563b
--- /dev/null
+++ b/std/zig.zig
@@ -0,0 +1,16 @@
+const tokenizer = @import("zig/tokenizer.zig");
+pub const Token = tokenizer.Token;
+pub const Tokenizer = tokenizer.Tokenizer;
+pub const parse = @import("zig/parse.zig").parse;
+pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStringLiteral;
+pub const render = @import("zig/render.zig").render;
+pub const ast = @import("zig/ast.zig");
+
+test "std.zig tests" {
+ _ = @import("zig/ast.zig");
+ _ = @import("zig/parse.zig");
+ _ = @import("zig/render.zig");
+ _ = @import("zig/tokenizer.zig");
+ _ = @import("zig/parse_string_literal.zig");
+}
+
diff --git a/std/zig/ast.zig b/std/zig/ast.zig
index ea32634566e94547bc2503f2f03d757d5d2a6c28..421c657619a3ca5a3be0c2fe9fe5b21d8a45e980 100644
--- a/std/zig/ast.zig
+++ b/std/zig/ast.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
const testing = std.testing;
const SegmentedList = std.SegmentedList;
@@ -617,7 +617,7 @@ pub const Node = struct {
pub const DeclList = Root.DeclList;
- const InitArg = union(enum) {
+ pub const InitArg = union(enum) {
None,
Enum: ?*Node,
Type: *Node,
@@ -1744,7 +1744,7 @@ pub const Node = struct {
kind: Kind,
rhs: ?*Node,
- const Kind = union(enum) {
+ pub const Kind = union(enum) {
Break: ?*Node,
Continue: ?*Node,
Return,
@@ -2022,7 +2022,7 @@ pub const Node = struct {
kind: Kind,
rparen: TokenIndex,
- const Kind = union(enum) {
+ pub const Kind = union(enum) {
Variable: *Identifier,
Return: *Node,
};
@@ -2101,9 +2101,9 @@ pub const Node = struct {
clobbers: ClobberList,
rparen: TokenIndex,
- const OutputList = SegmentedList(*AsmOutput, 2);
- const InputList = SegmentedList(*AsmInput, 2);
- const ClobberList = SegmentedList(TokenIndex, 2);
+ pub const OutputList = SegmentedList(*AsmOutput, 2);
+ pub const InputList = SegmentedList(*AsmInput, 2);
+ pub const ClobberList = SegmentedList(TokenIndex, 2);
pub fn iterate(self: *Asm, index: usize) ?*Node {
var i = index;
diff --git a/std/zig/bench.zig b/std/zig/bench.zig
index 6a9e8495bda00028c4d0135fd8ae62529097a786..ed6ae9a128b37a72c410b20460f1f8cd724a839e 100644
--- a/std/zig/bench.zig
+++ b/std/zig/bench.zig
@@ -5,7 +5,7 @@ const Tokenizer = std.zig.Tokenizer;
const Parser = std.zig.Parser;
const io = std.io;
-const source = @embedFile("../os/index.zig");
+const source = @embedFile("../os.zig");
var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
pub fn main() !void {
diff --git a/std/zig/index.zig b/std/zig/index.zig
deleted file mode 100644
index da84bc5bb0982db5d3acb608b5fac72250aa15fa..0000000000000000000000000000000000000000
--- a/std/zig/index.zig
+++ /dev/null
@@ -1,16 +0,0 @@
-const tokenizer = @import("tokenizer.zig");
-pub const Token = tokenizer.Token;
-pub const Tokenizer = tokenizer.Tokenizer;
-pub const parse = @import("parse.zig").parse;
-pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
-pub const render = @import("render.zig").render;
-pub const ast = @import("ast.zig");
-
-test "std.zig tests" {
- _ = @import("ast.zig");
- _ = @import("parse.zig");
- _ = @import("render.zig");
- _ = @import("tokenizer.zig");
- _ = @import("parse_string_literal.zig");
-}
-
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
index 867dd1159202b77e492085bb54b6eb1e238f0302..e957d1d3e1caa39d60117f8c7bde57217f0ef218 100644
--- a/std/zig/parse.zig
+++ b/std/zig/parse.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
const mem = std.mem;
const ast = std.zig.ast;
diff --git a/std/zig/parse_string_literal.zig b/std/zig/parse_string_literal.zig
index 00c92a7651e0251f21fdf65a2f3ec28c73b9c2a0..acae0b64c79c1d5c4251b8ed75f6691862f628c6 100644
--- a/std/zig/parse_string_literal.zig
+++ b/std/zig/parse_string_literal.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const assert = std.debug.assert;
const State = enum {
diff --git a/std/zig/render.zig b/std/zig/render.zig
index 1abc845b7c3103c8457e6f32d7740b1ed3b13ed8..50e928c0d878d4f2df97cd49a522f67a8f0d9e96 100644
--- a/std/zig/render.zig
+++ b/std/zig/render.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const mem = std.mem;
diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig
index 877e4e8db377951f352e90a2c3e2a67aff91a053..79fd1c5612830332457daf9e875be5dbc56f7cd6 100644
--- a/std/zig/tokenizer.zig
+++ b/std/zig/tokenizer.zig
@@ -1,4 +1,4 @@
-const std = @import("../index.zig");
+const std = @import("../std.zig");
const mem = std.mem;
pub const Token = struct {
diff --git a/test/build_examples.zig b/test/build_examples.zig
index c8a47bb0939f0cb4a659161b0a3d9dd65defa2ae..c51fdfdf894dfecd1e5fdd7e4f6caaaff0baed65 100644
--- a/test/build_examples.zig
+++ b/test/build_examples.zig
@@ -7,8 +7,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
cases.addC("example/hello_world/hello_libc.zig");
cases.add("example/cat/main.zig");
cases.add("example/guess_number/main.zig");
+ cases.addBuildFile("test/standalone/main_pkg_path/build.zig");
cases.addBuildFile("example/shared_library/build.zig");
cases.addBuildFile("example/mix_o_files/build.zig");
+ cases.addBuildFile("test/standalone/static_c_lib/build.zig");
if (builtin.os != builtin.Os.macosx) {
// TODO https://github.com/ziglang/zig/issues/1126
cases.addBuildFile("test/standalone/issue_339/build.zig");
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 1e6dc846050e0c60a5c41cc7c0f954310ad57632..92df4d2d1410c756a2e7a9da156652a1951f0a88 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,122 @@ const tests = @import("tests.zig");
const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.add(
+ "import outside package path",
+ \\comptime{
+ \\ _ = @import("../a.zig");
+ \\}
+ ,
+ "tmp.zig:2:9: error: import of file outside package path: '../a.zig'",
+ );
+
+ cases.add(
+ "bogus compile var",
+ \\const x = @import("builtin").bogus;
+ \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
+ ,
+ "tmp.zig:1:29: error: container 'builtin' has no member called 'bogus'",
+ );
+
+ cases.add(
+ "wrong panic signature, runtime function",
+ \\test "" {}
+ \\
+ \\pub fn panic() void {}
+ \\
+ ,
+ "tmp.zig:3:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'",
+ );
+
+ cases.add(
+ "wrong panic signature, generic function",
+ \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
+ \\ while (true) {}
+ \\}
+ ,
+ "tmp.zig:1:5: error: expected type 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn([]const u8,var)var'",
+ "tmp.zig:1:5: note: only one of the functions is generic",
+ );
+
+ cases.add(
+ "direct struct loop",
+ \\const A = struct { a : A, };
+ \\export fn entry() usize { return @sizeOf(A); }
+ ,
+ "tmp.zig:1:11: error: struct 'A' contains itself",
+ );
+
+ cases.add(
+ "indirect struct loop",
+ \\const A = struct { b : B, };
+ \\const B = struct { c : C, };
+ \\const C = struct { a : A, };
+ \\export fn entry() usize { return @sizeOf(A); }
+ ,
+ "tmp.zig:1:11: error: struct 'A' contains itself",
+ );
+
+ cases.add(
+ "instantiating an undefined value for an invalid struct that contains itself",
+ \\const Foo = struct {
+ \\ x: Foo,
+ \\};
+ \\
+ \\var foo: Foo = undefined;
+ \\
+ \\export fn entry() usize {
+ \\ return @sizeOf(@typeOf(foo.x));
+ \\}
+ ,
+ "tmp.zig:1:13: error: struct 'Foo' contains itself",
+ "tmp.zig:8:28: note: referenced here",
+ );
+
+ cases.add(
+ "@typeInfo causing depend on itself compile error",
+ \\const start = struct {
+ \\ fn crash() bug() {
+ \\ return bug;
+ \\ }
+ \\};
+ \\fn bug() void {
+ \\ _ = @typeInfo(start).Struct;
+ \\}
+ \\export fn entry() void {
+ \\ var boom = start.crash();
+ \\}
+ ,
+ "tmp.zig:7:9: error: dependency loop detected",
+ "tmp.zig:2:19: note: called from here",
+ "tmp.zig:10:21: note: referenced here",
+ );
+
+ cases.add(
+ "enum field value references enum",
+ \\pub const Foo = extern enum {
+ \\ A = Foo.B,
+ \\ C = D,
+ \\};
+ \\export fn entry() void {
+ \\ var s: Foo = Foo.E;
+ \\}
+ ,
+ "tmp.zig:1:17: error: 'Foo' depends on itself",
+ );
+
+ cases.add(
+ "top level decl dependency loop",
+ \\const a : @typeOf(b) = 0;
+ \\const b : @typeOf(a) = 0;
+ \\export fn entry() void {
+ \\ const c = a + b;
+ \\}
+ ,
+ "tmp.zig:2:19: error: dependency loop detected",
+ "tmp.zig:1:19: note: referenced here",
+ "tmp.zig:4:15: note: referenced here",
+ );
+
cases.addTest(
"not an enum type",
\\export fn entry() void {
@@ -18,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const InvalidToken = struct {};
\\const ExpectedVarDeclOrFn = struct {};
,
- ".tmp_source.zig:4:9: error: not an enum type",
+ "tmp.zig:4:9: error: not an enum type",
);
cases.addTest(
@@ -29,7 +145,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: AB = undefined;
\\}
,
- ".tmp_source.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
+ "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
);
if (builtin.os == builtin.Os.linux) {
@@ -40,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ exit(0);
\\}
,
- ".tmp_source.zig:3:5: error: dependency on library c must be explicitly specified in the build command",
+ "tmp.zig:3:5: error: dependency on library c must be explicitly specified in the build command",
);
cases.addTest(
@@ -50,8 +166,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = c.printf(c"hello, world!\n");
\\}
,
- ".tmp_source.zig:1:11: error: C import failed",
- ".tmp_source.zig:1:11: note: libc headers not available; compilation does not link against libc",
+ "tmp.zig:1:11: error: C import failed",
+ "tmp.zig:1:11: note: libc headers not available; compilation does not link against libc",
);
}
@@ -63,8 +179,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = a + b;
\\}
,
- ".tmp_source.zig:4:15: error: operation caused overflow",
- ".tmp_source.zig:4:15: note: when computing vector element at index 2",
+ "tmp.zig:4:15: error: operation caused overflow",
+ "tmp.zig:4:15: note: when computing vector element at index 2",
);
cases.addTest(
@@ -111,14 +227,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ B,
\\};
,
- ".tmp_source.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
- ".tmp_source.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
- ".tmp_source.zig:38:14: note: enum declaration does not specify an integer tag type",
+ "tmp.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
+ "tmp.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
+ "tmp.zig:38:14: note: enum declaration does not specify an integer tag type",
);
cases.addCase(x: {
@@ -131,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ x += 1;
\\}
,
- ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'",
+ "tmp.zig:2:5: error: use of undeclared identifier 'x'",
);
tc.expect_exact = true;
break :x tc;
@@ -143,7 +259,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 0;
\\}
,
- ".tmp_source.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'",
+ "tmp.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'",
);
cases.addTest(
@@ -153,7 +269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y: [*c]c_void = x;
\\}
,
- ".tmp_source.zig:3:12: error: C pointers cannot point opaque types",
+ "tmp.zig:3:12: error: C pointers cannot point opaque types",
);
cases.addTest(
@@ -173,8 +289,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bar: Bar = undefined;
\\}
,
- ".tmp_source.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
- ".tmp_source.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
+ "tmp.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
+ "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
);
cases.addTest(
@@ -204,13 +320,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: [*c]u32 = y;
\\}
,
- ".tmp_source.zig:3:27: error: cast increases pointer alignment",
- ".tmp_source.zig:7:18: error: cast discards const qualifier",
- ".tmp_source.zig:11:19: error: expected type '*u32', found '[*c]u8'",
- ".tmp_source.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
- ".tmp_source.zig:15:22: error: cast increases pointer alignment",
- ".tmp_source.zig:19:21: error: cast discards const qualifier",
- ".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'",
+ "tmp.zig:3:27: error: cast increases pointer alignment",
+ "tmp.zig:7:18: error: cast discards const qualifier",
+ "tmp.zig:11:19: error: expected type '*u32', found '[*c]u8'",
+ "tmp.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
+ "tmp.zig:15:22: error: cast increases pointer alignment",
+ "tmp.zig:19:21: error: cast discards const qualifier",
+ "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'",
);
cases.addTest(
@@ -220,7 +336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var zig_ptr: *u8 = c_ptr;
\\}
,
- ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'",
+ "tmp.zig:3:24: error: null pointer casted to type '*u8'",
);
cases.addTest(
@@ -230,7 +346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var zig_ptr: *u8 = c_ptr;
\\}
,
- ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:24: error: use of undefined value here causes undefined behavior",
);
cases.addTest(
@@ -250,12 +366,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
\\}
,
- ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
- ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
- ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
- ".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
- ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
- ".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
+ "tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
+ "tmp.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
+ "tmp.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
+ "tmp.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
+ "tmp.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
+ "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
);
cases.addTest(
@@ -268,8 +384,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var ptr: [*c]u8 = x;
\\}
,
- ".tmp_source.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
- ".tmp_source.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
+ "tmp.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
+ "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
);
cases.addTest(
@@ -279,7 +395,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const T = [*c]Foo;
\\}
,
- ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
+ "tmp.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
);
cases.addCase(x: {
@@ -294,7 +410,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); }
\\}
,
- ".tmp_source.zig:7:39: error: found compile log statement",
+ "tmp.zig:7:39: error: found compile log statement",
);
tc.expect_exact = true;
break :x tc;
@@ -306,7 +422,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ 'a'.* = 1;
\\}
,
- ".tmp_source.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
+ "tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
);
cases.addTest(
@@ -315,7 +431,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = 'a'.*[0..];
\\}
,
- ".tmp_source.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
+ "tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
);
cases.addTest(
@@ -324,14 +440,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var z = @truncate(u8, u16(undefined));
\\}
,
- ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:2:30: error: use of undefined value here causes undefined behavior",
);
cases.addTest(
"return invalid type from test",
\\test "example" { return 1; }
,
- ".tmp_source.zig:1:25: error: integer value 1 cannot be implicitly casted to type 'void'",
+ "tmp.zig:1:25: error: integer value 1 cannot be implicitly casted to type 'void'",
);
cases.add(
@@ -341,7 +457,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x;
\\}
,
- ".tmp_source.zig:1:13: error: threadlocal variable cannot be constant",
+ "tmp.zig:1:13: error: threadlocal variable cannot be constant",
);
cases.add(
@@ -350,7 +466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ threadlocal var x: i32 = 1234;
\\}
,
- ".tmp_source.zig:2:5: error: function-local variable 'x' cannot be threadlocal",
+ "tmp.zig:2:5: error: function-local variable 'x' cannot be threadlocal",
);
cases.add(
@@ -359,7 +475,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var oops = @bitCast(u7, byte);
\\}
,
- ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
+ "tmp.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
);
cases.add(
@@ -371,7 +487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 5678;
\\}
,
- ".tmp_source.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.",
+ "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.",
);
cases.add(
@@ -383,8 +499,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 5678;
\\}
,
- ".tmp_source.zig:2:9: error: expected error set type, found 'bool'",
- ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
+ "tmp.zig:2:9: error: expected error set type, found 'bool'",
+ "tmp.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
);
cases.add(
@@ -393,7 +509,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @compileLog(@ptrCast(*const c_void, &entry));
\\}
,
- ".tmp_source.zig:2:5: error: found compile log statement",
+ "tmp.zig:2:5: error: found compile log statement",
);
cases.add(
@@ -413,8 +529,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:5:9: error: duplicate switch value",
- ".tmp_source.zig:12:9: error: duplicate switch value",
+ "tmp.zig:5:9: error: duplicate switch value",
+ "tmp.zig:12:9: error: duplicate switch value",
);
cases.add(
@@ -430,8 +546,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:2:15: error: switch must handle all possibilities",
- ".tmp_source.zig:7:15: error: switch must handle all possibilities",
+ "tmp.zig:2:15: error: switch must handle all possibilities",
+ "tmp.zig:7:15: error: switch must handle all possibilities",
);
cases.add(
@@ -443,7 +559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const deref = int_ptr.*;
\\}
,
- ".tmp_source.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
+ "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
);
cases.add(
@@ -454,8 +570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ do_the_thing(bar);
\\}
,
- ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
- ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
+ "tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
+ "tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
);
cases.add(
@@ -469,8 +585,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const unsigned: u32 = value;
\\}
,
- ".tmp_source.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",
- ".tmp_source.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
+ "tmp.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",
+ "tmp.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
);
cases.add(
@@ -488,9 +604,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var byte: u8 = spartan_count;
\\}
,
- ".tmp_source.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'",
- ".tmp_source.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'",
- ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'",
+ "tmp.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'",
+ "tmp.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'",
+ "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
);
cases.add(
@@ -500,7 +616,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const y: f32 = x;
\\}
,
- ".tmp_source.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",
+ "tmp.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",
);
cases.add(
@@ -510,7 +626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'",
+ "tmp.zig:2:14: error: expected type 'f32', found 'f64'",
);
cases.add(
@@ -522,28 +638,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: i65536 = 1;
\\}
,
- ".tmp_source.zig:2:31: error: integer value 65536 cannot be implicitly casted to type 'u16'",
- ".tmp_source.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
- );
-
- cases.add(
- "wrong panic signature, runtime function",
- \\test "" {}
- \\
- \\pub fn panic() void {}
- \\
- ,
- ".tmp_source.zig:3:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn() void'",
- );
-
- cases.add(
- "wrong panic signature, generic function",
- \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
- \\ while (true) {}
- \\}
- ,
- ".tmp_source.zig:1:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn([]const u8,var)var'",
- ".tmp_source.zig:1:5: note: only one of the functions is generic",
+ "tmp.zig:2:31: error: integer value 65536 cannot be implicitly casted to type 'u16'",
+ "tmp.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
);
cases.add(
@@ -556,7 +652,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const car = Car.init();
\\}
,
- ".tmp_source.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
+ "tmp.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
);
cases.add(
@@ -568,7 +664,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var ptr2: *c_void = &b;
\\}
,
- ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'",
+ "tmp.zig:5:26: error: expected type '*c_void', found '**u32'",
);
cases.add(
@@ -584,7 +680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const field = @typeInfo(Struct).Struct.fields[index];
\\}
,
- ".tmp_source.zig:9:51: error: values of type 'StructField' must be comptime known, but index value is runtime known",
+ "tmp.zig:9:51: error: values of type 'builtin.StructField' must be comptime known, but index value is runtime known",
);
cases.add(
@@ -598,7 +694,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @typeName(Foo(i32));
\\}
,
- ".tmp_source.zig:2:5: error: found compile log statement",
+ "tmp.zig:2:5: error: found compile log statement",
);
cases.add(
@@ -608,7 +704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var b = a[0..10];
\\}
,
- ".tmp_source.zig:3:14: error: slice of undefined",
+ "tmp.zig:3:14: error: slice of undefined",
);
cases.add(
@@ -618,7 +714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const sliceA: []u8 = &buffer;
\\}
,
- ".tmp_source.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",
+ "tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",
);
cases.add(
@@ -628,7 +724,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a.*.len;
\\}
,
- ".tmp_source.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
+ "tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
);
cases.add(
@@ -639,9 +735,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return p == null;
\\}
,
- ".tmp_source.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation",
- ".tmp_source.zig:3:31: note: '*u0' has no in-memory bits",
- ".tmp_source.zig:3:24: note: '?*u0' has in-memory bits",
+ "tmp.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation",
+ "tmp.zig:3:31: note: '*u0' has no in-memory bits",
+ "tmp.zig:3:24: note: '?*u0' has in-memory bits",
);
cases.add(
@@ -651,7 +747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = &x == null;
\\}
,
- ".tmp_source.zig:3:12: error: comparison against null can only be done with optionals",
+ "tmp.zig:3:12: error: comparison against null can only be done with optionals",
);
cases.add(
@@ -663,10 +759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const Errors = error{} || u16;
\\}
,
- ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'",
- ".tmp_source.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
- ".tmp_source.zig:5:31: error: expected error set type, found type 'u16'",
- ".tmp_source.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
+ "tmp.zig:2:20: error: expected error set type, found type 'u8'",
+ "tmp.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
+ "tmp.zig:5:31: error: expected error set type, found type 'u16'",
+ "tmp.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
);
cases.add(
@@ -684,7 +780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const S = Gen();
\\}
,
- ".tmp_source.zig:2:12: error: use of undeclared identifier 'T'",
+ "tmp.zig:2:12: error: use of undeclared identifier 'T'",
);
cases.add(
@@ -695,7 +791,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f(i32);
\\}
,
- ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:4:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -713,9 +809,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = func(3);
\\}
,
- ".tmp_source.zig:4:24: error: 'y' not accessible from inner function",
- ".tmp_source.zig:3:28: note: crossed function definition here",
- ".tmp_source.zig:1:10: note: declared here",
+ "tmp.zig:4:24: error: 'y' not accessible from inner function",
+ "tmp.zig:3:28: note: crossed function definition here",
+ "tmp.zig:1:10: note: declared here",
);
cases.add(
@@ -724,7 +820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @intToFloat(f32, 1.1);
\\}
,
- ".tmp_source.zig:2:32: error: expected int type, found 'comptime_float'",
+ "tmp.zig:2:32: error: expected int type, found 'comptime_float'",
);
cases.add(
@@ -733,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @floatToInt(i32, i32(54));
\\}
,
- ".tmp_source.zig:2:35: error: expected float type, found 'i32'",
+ "tmp.zig:2:35: error: expected float type, found 'i32'",
);
cases.add(
@@ -742,7 +838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @floatToInt(i8, 200);
\\}
,
- ".tmp_source.zig:2:31: error: integer value 200 cannot be implicitly casted to type 'i8'",
+ "tmp.zig:2:31: error: integer value 200 cannot be implicitly casted to type 'i8'",
);
cases.add(
@@ -754,7 +850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const int_val = int_ptr.*;
\\}
,
- ".tmp_source.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",
+ "tmp.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",
);
cases.add(
@@ -767,7 +863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = items[0];
\\}
,
- ".tmp_source.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
+ "tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
);
cases.add(
@@ -778,7 +874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @noInlineCall(foo);
\\}
,
- ".tmp_source.zig:4:5: error: no-inline call of inline function",
+ "tmp.zig:4:5: error: no-inline call of inline function",
);
cases.add(
@@ -795,8 +891,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:6:19: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:6:19: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -812,8 +908,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:6:13: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:6:13: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -827,8 +923,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:23: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:5:23: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -842,8 +938,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:25: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:5:25: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -857,8 +953,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:5:20: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -872,8 +968,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:5:20: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -887,8 +983,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:22: error: comptime control flow inside runtime block",
- ".tmp_source.zig:5:9: note: runtime block created here",
+ "tmp.zig:5:22: error: comptime control flow inside runtime block",
+ "tmp.zig:5:9: note: runtime block created here",
);
cases.add(
@@ -904,7 +1000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:7:17: error: switch on type 'type' provides no expression parameter",
+ "tmp.zig:7:17: error: switch on type 'type' provides no expression parameter",
);
cases.add(
@@ -914,24 +1010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo();
\\}
,
- ".tmp_source.zig:1:1: error: non-extern function has no body",
- );
-
- cases.add(
- "@typeInfo causing depend on itself compile error",
- \\const start = struct {
- \\ fn crash() bug() {
- \\ return bug;
- \\ }
- \\};
- \\fn bug() void {
- \\ _ = @typeInfo(start).Struct;
- \\}
- \\export fn entry() void {
- \\ var boom = start.crash();
- \\}
- ,
- ".tmp_source.zig:2:5: error: 'crash' depends on itself",
+ "tmp.zig:1:1: error: non-extern function has no body",
);
cases.add(
@@ -942,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return handle_undef == handle_dummy;
\\}
,
- ".tmp_source.zig:2:29: error: @handle() called outside of function definition",
+ "tmp.zig:2:29: error: @handle() called outside of function definition",
);
cases.add(
@@ -952,7 +1031,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return handle_undef == @handle();
\\}
,
- ".tmp_source.zig:3:28: error: @handle() in non-async function",
+ "tmp.zig:3:28: error: @handle() in non-async function",
);
cases.add(
@@ -962,8 +1041,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return _;
\\}
,
- ".tmp_source.zig:2:5: error: `_` is not a declarable symbol",
- ".tmp_source.zig:3:12: error: use of undeclared identifier '_'",
+ "tmp.zig:2:5: error: `_` is not a declarable symbol",
+ "tmp.zig:3:12: error: use of undeclared identifier '_'",
);
cases.add(
@@ -976,7 +1055,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
+ "tmp.zig:4:20: error: use of undeclared identifier '_'",
);
cases.add(
@@ -992,7 +1071,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 1;
\\}
,
- ".tmp_source.zig:4:20: error: use of undeclared identifier '_'",
+ "tmp.zig:4:20: error: use of undeclared identifier '_'",
);
cases.add(
@@ -1010,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.optionalReturnError;
\\}
,
- ".tmp_source.zig:6:17: error: use of undeclared identifier '_'",
+ "tmp.zig:6:17: error: use of undeclared identifier '_'",
);
cases.add(
@@ -1030,9 +1109,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ while (x) |_| returns() else |_| unreachable;
\\}
,
- ".tmp_source.zig:5:25: error: expression value is ignored",
- ".tmp_source.zig:9:26: error: expression value is ignored",
- ".tmp_source.zig:13:26: error: expression value is ignored",
+ "tmp.zig:5:25: error: expression value is ignored",
+ "tmp.zig:9:26: error: expression value is ignored",
+ "tmp.zig:13:26: error: expression value is ignored",
);
cases.add(
@@ -1043,7 +1122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ dump(a);
\\}
,
- ".tmp_source.zig:1:9: error: missing parameter name",
+ "tmp.zig:1:9: error: missing parameter name",
);
cases.add(
@@ -1057,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ for (xx) |f| {}
\\}
,
- ".tmp_source.zig:7:15: error: variable of type 'Foo' must be const or comptime",
+ "tmp.zig:7:15: error: variable of type 'Foo' must be const or comptime",
);
cases.add(
@@ -1068,7 +1147,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f(g);
\\}
,
- ".tmp_source.zig:1:9: error: parameter of type 'fn(var)var' must be declared comptime",
+ "tmp.zig:1:9: error: parameter of type 'fn(var)var' must be declared comptime",
);
cases.add(
@@ -1082,7 +1161,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry(bar: *Bar) void {}
,
- ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
+ "tmp.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
);
cases.add(
@@ -1095,7 +1174,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ command.exec();
\\}
,
- ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -1108,7 +1187,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ command.exec();
\\}
,
- ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -1118,7 +1197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const aligned = @alignCast(4, ptr);
\\}
,
- ".tmp_source.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
+ "tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
);
cases.add(
@@ -1127,7 +1206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @ptrToInt(&{}) == @ptrToInt(&{});
\\}
,
- ".tmp_source.zig:2:23: error: pointer to size 0 type has no address",
+ "tmp.zig:2:23: error: pointer to size 0 type has no address",
);
cases.add(
@@ -1136,7 +1215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @popCount(x);
\\}
,
- ".tmp_source.zig:2:22: error: expected integer type, found 'f32'",
+ "tmp.zig:2:22: error: expected integer type, found 'f32'",
);
cases.add(
@@ -1145,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @popCount(-1);
\\}
,
- ".tmp_source.zig:2:9: error: @popCount on negative comptime_int value -1",
+ "tmp.zig:2:9: error: @popCount on negative comptime_int value -1",
);
cases.addCase(x: {
@@ -1161,10 +1240,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn bar(x: *b.Foo) void {}
,
- ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'",
- ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'",
- "a.zig:1:17: note: Foo declared here",
- "b.zig:1:17: note: Foo declared here",
+ "tmp.zig:6:10: error: expected type '*b.Foo', found '*a.Foo'",
+ "tmp.zig:6:10: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
+ "a.zig:1:17: note: a.Foo declared here",
+ "b.zig:1:17: note: b.Foo declared here",
);
tc.addSourceFile("a.zig",
@@ -1182,19 +1261,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
break :x tc;
});
- cases.add(
- "enum field value references enum",
- \\pub const Foo = extern enum {
- \\ A = Foo.B,
- \\ C = D,
- \\};
- \\export fn entry() void {
- \\ var s: Foo = Foo.E;
- \\}
- ,
- ".tmp_source.zig:1:17: error: 'Foo' depends on itself",
- );
-
cases.add(
"@floatToInt comptime safety",
\\comptime {
@@ -1207,9 +1273,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @floatToInt(u8, f32(256.1));
\\}
,
- ".tmp_source.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
- ".tmp_source.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
- ".tmp_source.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
+ "tmp.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
+ "tmp.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
+ "tmp.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
);
cases.add(
@@ -1218,7 +1284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: fn () c_void = undefined;
\\}
,
- ".tmp_source.zig:2:20: error: return type cannot be opaque",
+ "tmp.zig:2:20: error: return type cannot be opaque",
);
cases.add(
@@ -1231,7 +1297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y = p.*;
\\}
,
- ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'",
+ "tmp.zig:4:23: error: expected type '*?*i32', found '**i32'",
);
cases.add(
@@ -1240,7 +1306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x: [*]const bool = true;
\\}
,
- ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'",
+ "tmp.zig:2:30: error: expected type '[*]const bool', found 'bool'",
);
cases.add(
@@ -1249,7 +1315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x.*;
\\}
,
- ".tmp_source.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
+ "tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
);
cases.add(
@@ -1262,14 +1328,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo.a += 1;
\\}
,
- ".tmp_source.zig:6:8: error: type '[*]Foo' does not support field access",
+ "tmp.zig:6:8: error: type '[*]Foo' does not support field access",
);
cases.add(
"unknown length pointer to opaque",
\\export const T = [*]@OpaqueType();
,
- ".tmp_source.zig:1:18: error: unknown-length pointer to opaque",
+ "tmp.zig:1:18: error: unknown-length pointer to opaque",
);
cases.add(
@@ -1285,7 +1351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var rule_set = try Foo.init();
\\}
,
- ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'",
+ "tmp.zig:2:13: error: expected type 'i32', found 'type'",
);
cases.add(
@@ -1294,7 +1360,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const slice = ptr[0..2];
\\}
,
- ".tmp_source.zig:2:22: error: slice of single-item pointer",
+ "tmp.zig:2:22: error: slice of single-item pointer",
);
cases.add(
@@ -1303,7 +1369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return ptr[1];
\\}
,
- ".tmp_source.zig:2:15: error: index of single-item pointer",
+ "tmp.zig:2:15: error: index of single-item pointer",
);
cases.add(
@@ -1319,10 +1385,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return null;
\\}
,
- ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
- ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
- ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
- ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
+ "tmp.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
+ "tmp.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
+ "tmp.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
+ "tmp.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
);
cases.add(
@@ -1339,14 +1405,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ Filled,
\\};
,
- ".tmp_source.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
+ "tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
);
cases.add(
"invalid field access in comptime",
\\comptime { var x = doesnt_exist.whatever; }
,
- ".tmp_source.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",
+ "tmp.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",
);
cases.add(
@@ -1367,8 +1433,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:12:9: error: cannot suspend inside suspend block",
- ".tmp_source.zig:11:5: note: other suspend block here",
+ "tmp.zig:12:9: error: cannot suspend inside suspend block",
+ "tmp.zig:11:5: note: other suspend block here",
);
cases.add(
@@ -1378,8 +1444,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\inline fn b() void { }
,
- ".tmp_source.zig:2:5: error: functions marked inline must be stored in const or comptime var",
- ".tmp_source.zig:4:1: note: declared here",
+ "tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var",
+ "tmp.zig:4:1: note: declared here",
);
cases.add(
@@ -1389,7 +1455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @panic(e);
\\}
,
- ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",
+ "tmp.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",
);
cases.add(
@@ -1403,8 +1469,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var tagName = @tagName(fi);
\\}
,
- ".tmp_source.zig:7:19: error: union has no associated enum",
- ".tmp_source.zig:1:18: note: declared here",
+ "tmp.zig:7:19: error: union has no associated enum",
+ "tmp.zig:1:18: note: declared here",
);
cases.add(
@@ -1417,7 +1483,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.ShouldBeCompileError;
\\}
,
- ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
+ "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
);
cases.add(
@@ -1426,7 +1492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var s = (struct{v: var}){.v=i32(10)};
\\}
,
- ".tmp_source.zig:2:23: error: invalid token: 'var'",
+ "tmp.zig:2:23: error: invalid token: 'var'",
);
cases.add(
@@ -1436,7 +1502,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const y = @ptrCast(*i32, &x);
\\}
,
- ".tmp_source.zig:3:15: error: cast discards const qualifier",
+ "tmp.zig:3:15: error: cast discards const qualifier",
);
cases.add(
@@ -1445,7 +1511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const slice = ([*]i32)(undefined)[0..1];
\\}
,
- ".tmp_source.zig:2:38: error: non-zero length slice of undefined pointer",
+ "tmp.zig:2:38: error: non-zero length slice of undefined pointer",
);
cases.add(
@@ -1460,7 +1526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a(c);
\\}
,
- ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",
+ "tmp.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",
);
cases.add(
@@ -1474,7 +1540,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:5: error: else prong required when switching on type 'anyerror'",
+ "tmp.zig:5:5: error: else prong required when switching on type 'anyerror'",
);
cases.add(
@@ -1485,7 +1551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn foo() !void {
\\}
,
- ".tmp_source.zig:4:11: error: function with inferred error set must return at least one possible error",
+ "tmp.zig:4:11: error: function with inferred error set must return at least one possible error",
);
cases.add(
@@ -1504,8 +1570,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:2:26: error: error.Baz not handled in switch",
- ".tmp_source.zig:2:26: error: error.Bar not handled in switch",
+ "tmp.zig:2:26: error: error.Baz not handled in switch",
+ "tmp.zig:2:26: error: error.Bar not handled in switch",
);
cases.add(
@@ -1526,8 +1592,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
- ".tmp_source.zig:3:14: note: other value is here",
+ "tmp.zig:5:14: error: duplicate switch value: '@typeOf(foo).ReturnType.ErrorSet.Foo'",
+ "tmp.zig:3:14: note: other value is here",
);
cases.add("invalid cast from integral type to enum",
@@ -1542,7 +1608,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ E.One => {},
\\ }
\\}
- , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'");
+ , "tmp.zig:9:10: error: expected type 'usize', found 'E'");
cases.add(
"range operator in switch used on error set",
@@ -1560,7 +1626,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:3:17: error: operator not allowed for errors",
+ "tmp.zig:3:17: error: operator not allowed for errors",
);
cases.add(
@@ -1569,7 +1635,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const z: ?fn()!void = null;
\\}
,
- ".tmp_source.zig:2:15: error: inferring error set of return type valid only for function definitions",
+ "tmp.zig:2:15: error: inferring error set of return type valid only for function definitions",
);
cases.add(
@@ -1579,7 +1645,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const z = Foo.Bar;
\\}
,
- ".tmp_source.zig:3:18: error: no error named 'Bar' in 'Foo'",
+ "tmp.zig:3:18: error: no error named 'Bar' in 'Foo'",
);
cases.add(
@@ -1588,7 +1654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const z = i32!i32;
\\}
,
- ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'",
+ "tmp.zig:2:15: error: expected error set type, found type 'i32'",
);
cases.add(
@@ -1604,7 +1670,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",
+ "tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",
);
cases.add(
@@ -1613,7 +1679,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const z = error.A > error.B;
\\}
,
- ".tmp_source.zig:2:23: error: operator not allowed for errors",
+ "tmp.zig:2:23: error: operator not allowed for errors",
);
cases.add(
@@ -1625,7 +1691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y = @errSetCast(Set2, x);
\\}
,
- ".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",
+ "tmp.zig:5:13: error: error.B not a member of error set 'Set2'",
);
cases.add(
@@ -1638,9 +1704,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.B;
\\}
,
- ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'",
- ".tmp_source.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'",
- ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set",
+ "tmp.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'",
+ "tmp.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'",
+ "tmp.zig:3:35: note: cannot cast global error set into smaller set",
);
cases.add(
@@ -1653,10 +1719,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.B;
\\}
,
- ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
- ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",
+ "tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
+ "tmp.zig:3:31: note: cannot cast global error set into smaller set",
);
-
cases.add(
"recursive inferred error set",
\\export fn entry() void {
@@ -1666,7 +1731,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ try foo();
\\}
,
- ".tmp_source.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet",
+ "tmp.zig:5:5: error: cannot resolve inferred error set '@typeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet",
);
cases.add(
@@ -1680,8 +1745,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: Set2 = set1;
\\}
,
- ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'",
- ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",
+ "tmp.zig:7:19: error: expected type 'Set2', found 'Set1'",
+ "tmp.zig:1:23: note: 'error.B' not a member of destination error set",
);
cases.add(
@@ -1695,7 +1760,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y = @intToError(x);
\\}
,
- ".tmp_source.zig:7:13: error: integer value 3 represents no error",
+ "tmp.zig:7:13: error: integer value 3 represents no error",
);
cases.add(
@@ -1713,7 +1778,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y = @errSetCast(Set2, @intToError(x));
\\}
,
- ".tmp_source.zig:11:13: error: error.B not a member of error set 'Set2'",
+ "tmp.zig:11:13: error: error.B not a member of error set 'Set2'",
);
cases.add(
@@ -1722,7 +1787,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @memberCount(anyerror);
\\}
,
- ".tmp_source.zig:2:9: error: global error set member count not available at comptime",
+ "tmp.zig:2:9: error: global error set member count not available at comptime",
);
cases.add(
@@ -1735,8 +1800,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: Foo = undefined;
\\}
,
- ".tmp_source.zig:3:5: error: duplicate error: 'Bar'",
- ".tmp_source.zig:2:5: note: other error here",
+ "tmp.zig:3:5: error: duplicate error: 'Bar'",
+ "tmp.zig:2:5: note: other error here",
);
cases.add(
@@ -1745,7 +1810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = usize(-10);
\\}
,
- ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'",
+ "tmp.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'",
);
cases.add(
@@ -1755,7 +1820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var arr: [v]u8 = undefined;
\\}
,
- ".tmp_source.zig:1:1: error: unable to infer variable type",
+ "tmp.zig:1:1: error: unable to infer variable type",
);
cases.add(
@@ -1768,8 +1833,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: Foo = undefined;
\\}
,
- ".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",
- ".tmp_source.zig:2:5: note: other field here",
+ "tmp.zig:3:5: error: duplicate struct field: 'Bar'",
+ "tmp.zig:2:5: note: other field here",
);
cases.add(
@@ -1782,8 +1847,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: Foo = undefined;
\\}
,
- ".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",
- ".tmp_source.zig:2:5: note: other field here",
+ "tmp.zig:3:5: error: duplicate union field: 'Bar'",
+ "tmp.zig:2:5: note: other field here",
);
cases.add(
@@ -1797,8 +1862,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: Foo = undefined;
\\}
,
- ".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",
- ".tmp_source.zig:2:5: note: other field here",
+ "tmp.zig:3:5: error: duplicate enum field: 'Bar'",
+ "tmp.zig:2:5: note: other field here",
);
cases.add(
@@ -1808,15 +1873,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\nakedcc fn foo() void { }
,
- ".tmp_source.zig:2:5: error: unable to call function with naked calling convention",
- ".tmp_source.zig:4:1: note: declared here",
+ "tmp.zig:2:5: error: unable to call function with naked calling convention",
+ "tmp.zig:4:1: note: declared here",
);
cases.add(
"function with invalid return type",
\\export fn foo() boid {}
,
- ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'",
+ "tmp.zig:1:17: error: use of undeclared identifier 'boid'",
);
cases.add(
@@ -1824,7 +1889,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const Foo = enum { A, B, C };
\\export fn entry(foo: Foo) void { }
,
- ".tmp_source.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
+ "tmp.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -1836,7 +1901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry(foo: Foo) void { }
,
- ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
+ "tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -1848,7 +1913,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry(foo: Foo) void { }
,
- ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
+ "tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -1860,7 +1925,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ switch (f) {}
\\}
,
- ".tmp_source.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",
+ "tmp.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",
);
cases.add(
@@ -1869,7 +1934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = 1 >> -1;
\\}
,
- ".tmp_source.zig:2:18: error: shift by negative value -1",
+ "tmp.zig:2:18: error: shift by negative value -1",
);
cases.add(
@@ -1880,7 +1945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:3:9: error: encountered @panic at compile-time",
+ "tmp.zig:3:9: error: encountered @panic at compile-time",
);
cases.add(
@@ -1910,7 +1975,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ bogus;
\\}
,
- ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'",
+ "tmp.zig:8:5: error: use of undeclared identifier 'bogus'",
);
cases.add(
@@ -1923,7 +1988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:4:13: error: label not found: 'outer'",
+ "tmp.zig:4:13: error: label not found: 'outer'",
);
cases.add(
@@ -1937,7 +2002,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'",
+ "tmp.zig:5:13: error: labeled loop not found: 'outer'",
);
cases.add(
@@ -1950,8 +2015,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\extern fn bar(x: *void) void { }
,
- ".tmp_source.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
- ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
+ "tmp.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
+ "tmp.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -1963,7 +2028,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -1975,7 +2040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -1987,7 +2052,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -1999,7 +2064,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2011,7 +2076,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2023,7 +2088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2035,7 +2100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2047,7 +2112,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2059,7 +2124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2071,7 +2136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2083,7 +2148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2095,7 +2160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2107,7 +2172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2119,7 +2184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2131,7 +2196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2143,7 +2208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2155,7 +2220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2167,7 +2232,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2179,7 +2244,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2191,7 +2256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2203,7 +2268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
,
- ".tmp_source.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected token ';', found 'var'",
);
cases.add(
@@ -2212,7 +2277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn a() void {}
\\export fn entry() void { a(); }
,
- ".tmp_source.zig:2:1: error: redefinition of 'a'",
+ "tmp.zig:2:1: error: redefinition of 'a'",
);
cases.add(
@@ -2220,7 +2285,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn a() noreturn {return;}
\\export fn entry() void { a(); }
,
- ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'",
+ "tmp.zig:1:18: error: expected type 'noreturn', found 'void'",
);
cases.add(
@@ -2228,7 +2293,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn a() i32 {}
\\export fn entry() void { _ = a(); }
,
- ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'",
+ "tmp.zig:1:12: error: expected type 'i32', found 'void'",
);
cases.add(
@@ -2237,7 +2302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ b();
\\}
,
- ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
+ "tmp.zig:2:5: error: use of undeclared identifier 'b'",
);
cases.add(
@@ -2247,7 +2312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn b(a: i32, b: i32, c: i32) void { }
,
- ".tmp_source.zig:2:6: error: expected 3 arguments, found 1",
+ "tmp.zig:2:6: error: expected 3 arguments, found 1",
);
cases.add(
@@ -2255,7 +2320,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn a() bogus {}
\\export fn entry() void { _ = a(); }
,
- ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'",
+ "tmp.zig:1:8: error: use of undeclared identifier 'bogus'",
);
cases.add(
@@ -2263,7 +2328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn a() *noreturn {}
\\export fn entry() void { _ = a(); }
,
- ".tmp_source.zig:1:8: error: pointer to noreturn not allowed",
+ "tmp.zig:1:8: error: pointer to noreturn not allowed",
);
cases.add(
@@ -2275,7 +2340,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn b() void {}
,
- ".tmp_source.zig:3:5: error: unreachable code",
+ "tmp.zig:3:5: error: unreachable code",
);
cases.add(
@@ -2283,7 +2348,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const bogus = @import("bogus-does-not-exist.zig",);
\\export fn entry() void { bogus.bogo(); }
,
- ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
+ "tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
);
cases.add(
@@ -2294,8 +2359,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ c;
\\}
,
- ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
- ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'",
+ "tmp.zig:3:5: error: use of undeclared identifier 'b'",
+ "tmp.zig:4:5: error: use of undeclared identifier 'c'",
);
cases.add(
@@ -2304,7 +2369,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { f(1, 2); }
,
- ".tmp_source.zig:1:15: error: redeclaration of variable 'a'",
+ "tmp.zig:1:15: error: redeclaration of variable 'a'",
);
cases.add(
@@ -2314,7 +2379,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = 0;
\\}
,
- ".tmp_source.zig:3:5: error: redeclaration of variable 'a'",
+ "tmp.zig:3:5: error: redeclaration of variable 'a'",
);
cases.add(
@@ -2324,7 +2389,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { f(1); }
,
- ".tmp_source.zig:2:5: error: redeclaration of variable 'a'",
+ "tmp.zig:2:5: error: redeclaration of variable 'a'",
);
cases.add(
@@ -2334,7 +2399,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return a;
\\}
,
- ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'",
+ "tmp.zig:3:12: error: expected type 'i32', found '[*]const u8'",
);
cases.add(
@@ -2343,7 +2408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ if (0) {}
\\}
,
- ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'",
+ "tmp.zig:2:9: error: expected type 'bool', found 'comptime_int'",
);
cases.add(
@@ -2352,7 +2417,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = return;
\\}
,
- ".tmp_source.zig:2:5: error: unreachable code",
+ "tmp.zig:2:5: error: unreachable code",
);
cases.add(
@@ -2361,7 +2426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: noreturn = {};
\\}
,
- ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed",
+ "tmp.zig:2:14: error: variable of type 'noreturn' not allowed",
);
cases.add(
@@ -2369,7 +2434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn f(a: noreturn) void {}
\\export fn entry() void { f(); }
,
- ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed",
+ "tmp.zig:1:9: error: parameter of type 'noreturn' not allowed",
);
cases.add(
@@ -2378,7 +2443,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ 3 = 3;
\\}
,
- ".tmp_source.zig:2:7: error: cannot assign to constant",
+ "tmp.zig:2:7: error: cannot assign to constant",
);
cases.add(
@@ -2388,7 +2453,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a = 4;
\\}
,
- ".tmp_source.zig:3:7: error: cannot assign to constant",
+ "tmp.zig:3:7: error: cannot assign to constant",
);
cases.add(
@@ -2397,7 +2462,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ b = 3;
\\}
,
- ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
+ "tmp.zig:2:5: error: use of undeclared identifier 'b'",
);
cases.add(
@@ -2406,7 +2471,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ (const a = 0);
\\}
,
- ".tmp_source.zig:2:6: error: invalid token: 'const'",
+ "tmp.zig:2:6: error: invalid token: 'const'",
);
cases.add(
@@ -2415,7 +2480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ i[i] = i[i];
\\}
,
- ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
+ "tmp.zig:2:5: error: use of undeclared identifier 'i'",
);
cases.add(
@@ -2425,8 +2490,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ bad[bad] = bad[bad];
\\}
,
- ".tmp_source.zig:3:8: error: array access of non-array type 'bool'",
- ".tmp_source.zig:3:19: error: array access of non-array type 'bool'",
+ "tmp.zig:3:8: error: array access of non-array type 'bool'",
+ "tmp.zig:3:19: error: array access of non-array type 'bool'",
);
cases.add(
@@ -2437,8 +2502,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ array[bad] = array[bad];
\\}
,
- ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",
- ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'",
+ "tmp.zig:4:11: error: expected type 'usize', found 'bool'",
+ "tmp.zig:4:24: error: expected type 'usize', found 'bool'",
);
cases.add(
@@ -2449,7 +2514,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { f(); }
,
- ".tmp_source.zig:3:7: error: cannot assign to constant",
+ "tmp.zig:3:7: error: cannot assign to constant",
);
cases.add(
@@ -2460,26 +2525,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { f(true); }
,
- ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
- ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'",
- );
-
- cases.add(
- "direct struct loop",
- \\const A = struct { a : A, };
- \\export fn entry() usize { return @sizeOf(A); }
- ,
- ".tmp_source.zig:1:11: error: struct 'A' contains itself",
- );
-
- cases.add(
- "indirect struct loop",
- \\const A = struct { b : B, };
- \\const B = struct { c : C, };
- \\const C = struct { a : A, };
- \\export fn entry() usize { return @sizeOf(A); }
- ,
- ".tmp_source.zig:1:11: error: struct 'A' contains itself",
+ "tmp.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
+ "tmp.zig:3:15: error: incompatible types: 'i32' and 'void'",
);
cases.add(
@@ -2491,8 +2538,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const y = a.bar;
\\}
,
- ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
- ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'",
+ "tmp.zig:4:6: error: no member named 'foo' in struct 'A'",
+ "tmp.zig:5:16: error: no member named 'bar' in struct 'A'",
);
cases.add(
@@ -2500,7 +2547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const A = struct { x : i32, };
\\const A = struct { y : i32, };
,
- ".tmp_source.zig:2:1: error: redefinition of 'A'",
+ "tmp.zig:2:1: error: redefinition of 'A'",
);
cases.add(
@@ -2508,7 +2555,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const A = enum {};
\\const A = enum {};
,
- ".tmp_source.zig:2:1: error: redefinition of 'A'",
+ "tmp.zig:2:1: error: redefinition of 'A'",
);
cases.add(
@@ -2516,8 +2563,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\var a : i32 = 1;
\\var a : i32 = 2;
,
- ".tmp_source.zig:2:1: error: redefinition of 'a'",
- ".tmp_source.zig:1:1: note: previous definition is here",
+ "tmp.zig:2:1: error: redefinition of 'a'",
+ "tmp.zig:1:1: note: previous definition is here",
);
cases.add(
@@ -2536,7 +2583,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:11:9: error: duplicate field",
+ "tmp.zig:11:9: error: duplicate field",
);
cases.add(
@@ -2555,7 +2602,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:9:17: error: missing field: 'x'",
+ "tmp.zig:9:17: error: missing field: 'x'",
);
cases.add(
@@ -2573,7 +2620,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'",
+ "tmp.zig:10:9: error: no member named 'foo' in struct 'A'",
);
cases.add(
@@ -2582,7 +2629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ break;
\\}
,
- ".tmp_source.zig:2:5: error: break expression outside loop",
+ "tmp.zig:2:5: error: break expression outside loop",
);
cases.add(
@@ -2591,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ continue;
\\}
,
- ".tmp_source.zig:2:5: error: continue expression outside loop",
+ "tmp.zig:2:5: error: continue expression outside loop",
);
cases.add(
@@ -2600,7 +2647,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ if (true) |x| { }
\\}
,
- ".tmp_source.zig:2:9: error: expected optional type, found 'bool'",
+ "tmp.zig:2:9: error: expected optional type, found 'bool'",
);
cases.add(
@@ -2610,7 +2657,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { _ = f(); }
,
- ".tmp_source.zig:2:15: error: unreachable code",
+ "tmp.zig:2:15: error: unreachable code",
);
cases.add(
@@ -2619,18 +2666,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { _ = f(); }
,
- ".tmp_source.zig:1:8: error: invalid builtin function: 'bogus'",
- );
-
- cases.add(
- "top level decl dependency loop",
- \\const a : @typeOf(b) = 0;
- \\const b : @typeOf(a) = 0;
- \\export fn entry() void {
- \\ const c = a + b;
- \\}
- ,
- ".tmp_source.zig:1:1: error: 'a' depends on itself",
+ "tmp.zig:1:8: error: invalid builtin function: 'bogus'",
);
cases.add(
@@ -2638,7 +2674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn f(noalias x: i32) void {}
\\export fn entry() void { f(1234); }
,
- ".tmp_source.zig:1:6: error: noalias on non-pointer parameter",
+ "tmp.zig:1:6: error: noalias on non-pointer parameter",
);
cases.add(
@@ -2646,7 +2682,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const foo = []u16{.x = 1024,};
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax",
+ "tmp.zig:1:18: error: type '[]u16' does not support struct initialization syntax",
);
cases.add(
@@ -2656,7 +2692,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 1;
\\}
,
- ".tmp_source.zig:1:1: error: variable of type 'type' must be constant",
+ "tmp.zig:1:1: error: variable of type 'type' must be constant",
);
cases.add(
@@ -2672,10 +2708,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f(1234);
\\}
,
- ".tmp_source.zig:4:6: error: redefinition of 'Foo'",
- ".tmp_source.zig:1:1: note: previous definition is here",
- ".tmp_source.zig:5:5: error: redefinition of 'Bar'",
- ".tmp_source.zig:2:1: note: previous definition is here",
+ "tmp.zig:4:6: error: redefinition of 'Foo'",
+ "tmp.zig:1:1: note: previous definition is here",
+ "tmp.zig:5:5: error: redefinition of 'Bar'",
+ "tmp.zig:2:1: note: previous definition is here",
);
cases.add(
@@ -2696,7 +2732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",
+ "tmp.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",
);
cases.add(
@@ -2719,8 +2755,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:13:15: error: duplicate switch value",
- ".tmp_source.zig:10:15: note: other value is here",
+ "tmp.zig:13:15: error: duplicate switch value",
+ "tmp.zig:10:15: note: other value is here",
);
cases.add(
@@ -2744,8 +2780,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:13:15: error: duplicate switch value",
- ".tmp_source.zig:10:15: note: other value is here",
+ "tmp.zig:13:15: error: duplicate switch value",
+ "tmp.zig:10:15: note: other value is here",
);
cases.add(
@@ -2761,7 +2797,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f(1234);
\\}
,
- ".tmp_source.zig:5:9: error: multiple else prongs in switch expression",
+ "tmp.zig:5:9: error: multiple else prongs in switch expression",
);
cases.add(
@@ -2773,7 +2809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:2:5: error: switch must handle all possibilities",
+ "tmp.zig:2:5: error: switch must handle all possibilities",
);
cases.add(
@@ -2788,8 +2824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:6:9: error: duplicate switch value",
- ".tmp_source.zig:5:14: note: previous value is here",
+ "tmp.zig:6:9: error: duplicate switch value",
+ "tmp.zig:5:14: note: previous value is here",
);
cases.add(
@@ -2802,7 +2838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const y: u8 = 100;
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:2:5: error: else prong required when switching on type '*u8'",
+ "tmp.zig:2:5: error: else prong required when switching on type '*u8'",
);
cases.add(
@@ -2811,7 +2847,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const x = foo();
\\export fn entry() i32 { return x; }
,
- ".tmp_source.zig:2:11: error: unable to evaluate constant expression",
+ "tmp.zig:2:11: error: unable to evaluate constant expression",
);
cases.add(
@@ -2822,7 +2858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'",
+ "tmp.zig:3:11: error: expected array or C string literal, found 'usize'",
);
cases.add(
@@ -2833,7 +2869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\var s: [10]u8 = undefined;
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:2:12: error: unable to evaluate constant expression",
+ "tmp.zig:2:12: error: unable to evaluate constant expression",
);
cases.add(
@@ -2841,7 +2877,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const c = @cImport(@cInclude("bogus.h"));
\\export fn entry() usize { return @sizeOf(@typeOf(c.bogo)); }
,
- ".tmp_source.zig:1:11: error: C import failed",
+ "tmp.zig:1:11: error: C import failed",
".h:1:10: note: 'bogus.h' file not found",
);
@@ -2852,7 +2888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn foo() *const i32 { return y; }
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",
+ "tmp.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",
);
cases.add(
@@ -2860,7 +2896,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const x : u8 = 300;
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
,
- ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
+ "tmp.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
);
cases.add(
@@ -2871,8 +2907,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() u16 { return f(); }
,
- ".tmp_source.zig:3:14: error: RHS of shift is too large for LHS type",
- ".tmp_source.zig:3:17: note: value 8 cannot fit into type u3",
+ "tmp.zig:3:14: error: RHS of shift is too large for LHS type",
+ "tmp.zig:3:17: note: value 8 cannot fit into type u3",
);
cases.add(
@@ -2880,7 +2916,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const x = 2 == 2.0;
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
,
- ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",
+ "tmp.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",
);
cases.add(
@@ -2909,7 +2945,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:20:34: error: expected 1 arguments, found 0",
+ "tmp.zig:20:34: error: expected 1 arguments, found 0",
);
cases.add(
@@ -2918,8 +2954,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn f(i32) void {}
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:1:1: error: missing function name",
- ".tmp_source.zig:2:6: error: missing parameter name",
+ "tmp.zig:1:1: error: missing function name",
+ "tmp.zig:2:6: error: missing parameter name",
);
cases.add(
@@ -2930,7 +2966,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn c() i32 {return 2;}
\\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
,
- ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'",
+ "tmp.zig:1:27: error: expected type 'fn() void', found 'fn() i32'",
);
cases.add(
@@ -2942,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(fns)); }
,
- ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",
+ "tmp.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",
);
cases.add(
@@ -2951,16 +2987,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn func() bogus {}
\\export fn entry() usize { return @sizeOf(@typeOf(func)); }
,
- ".tmp_source.zig:2:1: error: redefinition of 'func'",
- ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'",
- );
-
- cases.add(
- "bogus compile var",
- \\const x = @import("builtin").bogus;
- \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
- ,
- ".tmp_source.zig:1:29: error: no member named 'bogus' in '",
+ "tmp.zig:2:1: error: redefinition of 'func'",
+ "tmp.zig:1:11: error: use of undeclared identifier 'bogus'",
);
cases.add(
@@ -2973,9 +3001,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
,
- ".tmp_source.zig:5:25: error: unable to evaluate constant expression",
- ".tmp_source.zig:2:12: note: called from here",
- ".tmp_source.zig:2:8: note: called from here",
+ "tmp.zig:5:25: error: unable to evaluate constant expression",
+ "tmp.zig:2:12: note: called from here",
+ "tmp.zig:2:8: note: called from here",
);
cases.add(
@@ -2987,7 +3015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
,
- ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",
+ "tmp.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",
);
cases.add(
@@ -3002,10 +3030,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry3() usize { return @sizeOf(@typeOf(int_x)); }
\\export fn entry4() usize { return @sizeOf(@typeOf(float_x)); }
,
- ".tmp_source.zig:1:21: error: division by zero",
- ".tmp_source.zig:2:25: error: division by zero",
- ".tmp_source.zig:3:22: error: division by zero",
- ".tmp_source.zig:4:26: error: division by zero",
+ "tmp.zig:1:21: error: division by zero",
+ "tmp.zig:2:25: error: division by zero",
+ "tmp.zig:3:22: error: division by zero",
+ "tmp.zig:4:26: error: division by zero",
);
cases.add(
@@ -3015,7 +3043,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:1:15: error: newline not allowed in string literal",
+ "tmp.zig:1:15: error: newline not allowed in string literal",
);
cases.add(
@@ -3025,7 +3053,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(invalid)); }
,
- ".tmp_source.zig:2:21: error: operator not allowed for type 'fn() void'",
+ "tmp.zig:2:21: error: operator not allowed for type 'fn() void'",
);
cases.add(
@@ -3037,7 +3065,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(test1)); }
,
- ".tmp_source.zig:3:16: error: unable to evaluate constant expression",
+ "tmp.zig:3:16: error: unable to evaluate constant expression",
);
cases.add(
@@ -3046,7 +3074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'",
+ "tmp.zig:1:16: error: expected type '*u8', found '(null)'",
);
cases.add(
@@ -3056,7 +3084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const pointer = &array[0];
\\}
,
- ".tmp_source.zig:3:27: error: index 0 outside array of size 0",
+ "tmp.zig:3:27: error: index 0 outside array of size 0",
);
cases.add(
@@ -3068,8 +3096,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:3:14: error: division by zero",
- ".tmp_source.zig:1:14: note: called from here",
+ "tmp.zig:3:14: error: division by zero",
+ "tmp.zig:1:14: note: called from here",
);
cases.add(
@@ -3078,7 +3106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
,
- ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:1:15: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3088,7 +3116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a / a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3098,7 +3126,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a /= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3108,7 +3136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a % a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3118,7 +3146,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a %= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3128,7 +3156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a + a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3138,7 +3166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a += a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3148,7 +3176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a +% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3158,7 +3186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a +%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3168,7 +3196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a - a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3178,7 +3206,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a -= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3188,7 +3216,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a -% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3198,7 +3226,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a -%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3208,7 +3236,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a * a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3218,7 +3246,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a *= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3228,7 +3256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a *% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3238,7 +3266,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a *%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3248,7 +3276,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a << 2;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3258,7 +3286,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a <<= 2;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3268,7 +3296,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a >> 2;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3278,7 +3306,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a >>= 2;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3288,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a & a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3298,7 +3326,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a &= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3308,7 +3336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a | a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3318,7 +3346,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a |= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3328,7 +3356,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a ^ a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3338,7 +3366,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a ^= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3348,7 +3376,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a == a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3358,7 +3386,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a != a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3368,7 +3396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a > a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3378,7 +3406,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a >= a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3388,7 +3416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a < a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3398,7 +3426,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a <= a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3408,7 +3436,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a and a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3418,7 +3446,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a or a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3428,7 +3456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = -a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3438,7 +3466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = -%a;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3448,7 +3476,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = ~a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3458,7 +3486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = !a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3468,7 +3496,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a orelse false;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3478,7 +3506,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a catch |err| false;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3488,7 +3516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a.*;
\\}
,
- ".tmp_source.zig:3:9: error: attempt to dereference undefined value",
+ "tmp.zig:3:9: error: attempt to dereference undefined value",
);
cases.add(
@@ -3500,8 +3528,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); }
,
- ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
- ".tmp_source.zig:3:21: note: called from here",
+ "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches",
+ "tmp.zig:3:21: note: called from here",
);
cases.add(
@@ -3510,7 +3538,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(resource)); }
,
- ".tmp_source.zig:1:29: error: unable to find '",
+ "tmp.zig:1:29: error: unable to find '",
"bogus.txt'",
);
@@ -3524,7 +3552,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:4:21: error: unable to evaluate constant expression",
+ "tmp.zig:4:21: error: unable to evaluate constant expression",
);
cases.add(
@@ -3541,8 +3569,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
- ".tmp_source.zig:4:17: note: called from here",
+ "tmp.zig:6:24: error: unable to evaluate constant expression",
+ "tmp.zig:4:17: note: called from here",
);
cases.add(
@@ -3554,7 +3582,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ bad_fn_call();
\\}
,
- ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",
+ "tmp.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",
);
cases.add(
@@ -3573,8 +3601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry1() usize { return @sizeOf(@typeOf(bad_eql_1)); }
\\export fn entry2() usize { return @sizeOf(@typeOf(bad_eql_2)); }
,
- ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
- ".tmp_source.zig:9:16: error: operator not allowed for type 'EnumWithData'",
+ "tmp.zig:2:14: error: operator not allowed for type '[]u8'",
+ "tmp.zig:9:16: error: operator not allowed for type 'EnumWithData'",
);
cases.add(
@@ -3590,7 +3618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 2;
\\}
,
- ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known",
+ "tmp.zig:2:15: error: values of type 'comptime_int' must be comptime known",
);
cases.add(
@@ -3601,7 +3629,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
\\}
,
- ".tmp_source.zig:4:81: error: failure atomic ordering must be no stricter than success",
+ "tmp.zig:4:81: error: failure atomic ordering must be no stricter than success",
);
cases.add(
@@ -3612,7 +3640,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
\\}
,
- ".tmp_source.zig:4:58: error: success atomic ordering must be Monotonic or stricter",
+ "tmp.zig:4:58: error: success atomic ordering must be Monotonic or stricter",
);
cases.add(
@@ -3624,8 +3652,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:3:12: error: negation caused overflow",
- ".tmp_source.zig:1:14: note: called from here",
+ "tmp.zig:3:12: error: negation caused overflow",
+ "tmp.zig:1:14: note: called from here",
);
cases.add(
@@ -3637,8 +3665,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:3:14: error: operation caused overflow",
- ".tmp_source.zig:1:14: note: called from here",
+ "tmp.zig:3:14: error: operation caused overflow",
+ "tmp.zig:1:14: note: called from here",
);
cases.add(
@@ -3650,8 +3678,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:3:14: error: operation caused overflow",
- ".tmp_source.zig:1:14: note: called from here",
+ "tmp.zig:3:14: error: operation caused overflow",
+ "tmp.zig:1:14: note: called from here",
);
cases.add(
@@ -3663,8 +3691,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(y)); }
,
- ".tmp_source.zig:3:14: error: operation caused overflow",
- ".tmp_source.zig:1:14: note: called from here",
+ "tmp.zig:3:14: error: operation caused overflow",
+ "tmp.zig:1:14: note: called from here",
);
cases.add(
@@ -3676,7 +3704,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'",
+ "tmp.zig:3:26: error: expected signed integer type, found 'u32'",
);
cases.add(
@@ -3686,8 +3714,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn something() anyerror!void { }
,
- ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'",
- ".tmp_source.zig:1:15: note: return type declared here",
+ "tmp.zig:2:5: error: expected type 'void', found 'anyerror'",
+ "tmp.zig:1:15: note: return type declared here",
);
cases.add(
@@ -3700,7 +3728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:2:13: error: unable to evaluate constant expression",
+ "tmp.zig:2:13: error: unable to evaluate constant expression",
);
cases.add(
@@ -3709,7 +3737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x + y;
\\}
,
- ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
+ "tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -3720,7 +3748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
+ "tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'",
);
cases.add(
@@ -3730,8 +3758,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var foo = @bytesToSlice(u32, array)[0];
\\}
,
- ".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
- ".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",
+ "tmp.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
+ "tmp.zig:3:29: note: u32 has size 4; remaining bytes: 1",
);
cases.add(
@@ -3755,8 +3783,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ list.length = 10;
\\}
,
- ".tmp_source.zig:3:7: error: unable to evaluate constant expression",
- ".tmp_source.zig:16:19: note: called from here",
+ "tmp.zig:3:7: error: unable to evaluate constant expression",
+ "tmp.zig:16:19: note: called from here",
);
cases.add(
@@ -3767,7 +3795,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'",
+ "tmp.zig:3:6: error: no member named 'copy' in '[]const u8'",
);
cases.add(
@@ -3781,7 +3809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() usize { return @sizeOf(@typeOf(f)); }
,
- ".tmp_source.zig:6:15: error: expected 2 arguments, found 3",
+ "tmp.zig:6:15: error: expected 2 arguments, found 3",
);
cases.add(
@@ -3791,7 +3819,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ cstr[0] = 'W';
\\}
,
- ".tmp_source.zig:3:11: error: cannot assign to constant",
+ "tmp.zig:3:11: error: cannot assign to constant",
);
cases.add(
@@ -3801,14 +3829,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ cstr[0] = 'W';
\\}
,
- ".tmp_source.zig:3:11: error: cannot assign to constant",
+ "tmp.zig:3:11: error: cannot assign to constant",
);
cases.add(
"main function with bogus args type",
\\pub fn main(args: [][]bogus) !void {}
,
- ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'",
+ "tmp.zig:1:23: error: use of undeclared identifier 'bogus'",
);
cases.add(
@@ -3844,7 +3872,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'",
+ "tmp.zig:5:16: error: use of undeclared identifier 'JsonList'",
);
cases.add(
@@ -3865,7 +3893,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ derp.init();
\\}
,
- ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
+ "tmp.zig:14:5: error: expected type 'i32', found 'Foo'",
);
cases.add(
@@ -3895,7 +3923,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ x.init();
\\}
,
- ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'",
+ "tmp.zig:23:5: error: expected type '*Allocator', found '*List'",
);
cases.add(
@@ -3906,7 +3934,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
,
- ".tmp_source.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",
+ "tmp.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",
);
cases.addCase(x: {
@@ -3918,7 +3946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo.privateFunction();
\\}
,
- ".tmp_source.zig:4:8: error: 'privateFunction' is private",
+ "tmp.zig:4:8: error: 'privateFunction' is private",
"foo.zig:1:1: note: declared here",
);
@@ -3936,7 +3964,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'",
+ "tmp.zig:2:11: error: expected type 'type', found 'i32'",
);
cases.add(
@@ -3949,7 +3977,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f.field = 0;
\\}
,
- ".tmp_source.zig:6:13: error: cannot assign to constant",
+ "tmp.zig:6:13: error: cannot assign to constant",
);
cases.add(
@@ -3970,7 +3998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(testTrickyDefer)); }
,
- ".tmp_source.zig:4:11: error: cannot return from defer expression",
+ "tmp.zig:4:11: error: cannot return from defer expression",
);
cases.add(
@@ -3985,8 +4013,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
- ".tmp_source.zig:6:15: note: called from here",
+ "tmp.zig:2:26: error: index 1 outside argument list of size 1",
+ "tmp.zig:6:15: note: called from here",
);
cases.add(
@@ -4005,7 +4033,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(bar)); }
,
- ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted",
+ "tmp.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted",
);
cases.add(
@@ -4014,7 +4042,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var vga_mem: u16 = 0xB8000;
\\}
,
- ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'",
+ "tmp.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'",
);
cases.add(
@@ -4022,7 +4050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\const some_data: [100]u8 align(3) = undefined;
\\export fn entry() usize { return @sizeOf(@typeOf(some_data)); }
,
- ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2",
+ "tmp.zig:1:32: error: alignment value 3 is not a power of 2",
);
cases.add(
@@ -4030,7 +4058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\extern fn foo() align(3) void;
\\export fn entry() void { return foo(); }
,
- ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2",
+ "tmp.zig:1:23: error: alignment value 3 is not a power of 2",
);
cases.add(
@@ -4044,9 +4072,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @compileLog("end",);
\\}
,
- ".tmp_source.zig:5:5: error: found compile log statement",
- ".tmp_source.zig:6:5: error: found compile log statement",
- ".tmp_source.zig:7:5: error: found compile log statement",
+ "tmp.zig:5:5: error: found compile log statement",
+ "tmp.zig:6:5: error: found compile log statement",
+ "tmp.zig:7:5: error: found compile log statement",
);
cases.add(
@@ -4067,7 +4095,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",
+ "tmp.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",
);
cases.add(
@@ -4084,8 +4112,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ if (!ok) unreachable;
\\}
,
- ".tmp_source.zig:10:14: error: unable to evaluate constant expression",
- ".tmp_source.zig:6:20: note: called from here",
+ "tmp.zig:10:14: error: unable to evaluate constant expression",
+ "tmp.zig:6:20: note: called from here",
);
cases.add(
@@ -4099,8 +4127,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn bar() void { }
,
- ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
- ".tmp_source.zig:3:24: note: compile-time variable assigned here",
+ "tmp.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
+ "tmp.zig:3:24: note: compile-time variable assigned here",
);
cases.add(
@@ -4110,7 +4138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() i32 { return 0; }
,
- ".tmp_source.zig:2:8: error: expression value is ignored",
+ "tmp.zig:2:8: error: expression value is ignored",
);
cases.add(
@@ -4120,7 +4148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() anyerror!i32 { return 0; }
,
- ".tmp_source.zig:2:11: error: expression value is ignored",
+ "tmp.zig:2:11: error: expression value is ignored",
);
cases.add(
@@ -4129,7 +4157,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ 1;
\\}
,
- ".tmp_source.zig:2:5: error: expression value is ignored",
+ "tmp.zig:2:5: error: expression value is ignored",
);
cases.add(
@@ -4138,7 +4166,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ comptime {1;}
\\}
,
- ".tmp_source.zig:2:15: error: expression value is ignored",
+ "tmp.zig:2:15: error: expression value is ignored",
);
cases.add(
@@ -4147,7 +4175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ comptime 1;
\\}
,
- ".tmp_source.zig:2:5: error: expression value is ignored",
+ "tmp.zig:2:5: error: expression value is ignored",
);
cases.add(
@@ -4156,7 +4184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ defer {1;}
\\}
,
- ".tmp_source.zig:2:12: error: expression value is ignored",
+ "tmp.zig:2:12: error: expression value is ignored",
);
cases.add(
@@ -4166,7 +4194,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() anyerror!i32 { return 0; }
,
- ".tmp_source.zig:2:14: error: expression value is ignored",
+ "tmp.zig:2:14: error: expression value is ignored",
);
cases.add(
@@ -4180,7 +4208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
,
- ".tmp_source.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
+ "tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
);
cases.add(
@@ -4196,7 +4224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
,
- ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",
+ "tmp.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",
);
cases.addCase(x: {
@@ -4209,7 +4237,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
,
"foo.zig:1:1: error: exported symbol collision: 'bar'",
- ".tmp_source.zig:3:1: note: other symbol here",
+ "tmp.zig:3:1: note: other symbol here",
);
tc.addSourceFile("foo.zig",
@@ -4228,7 +4256,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo(global_array);
\\}
,
- ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'",
+ "tmp.zig:4:9: error: expected type '[]i32', found '[10]i32'",
);
cases.add(
@@ -4237,7 +4265,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @ptrCast(usize, a);
\\}
,
- ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",
+ "tmp.zig:2:21: error: expected pointer, found 'usize'",
);
cases.add(
@@ -4254,7 +4282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ );
\\}
,
- ".tmp_source.zig:6:5: error: unable to evaluate constant expression",
+ "tmp.zig:6:5: error: unable to evaluate constant expression",
);
cases.add(
@@ -4264,7 +4292,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const foo = builtin.Arch.x86;
\\}
,
- ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'",
+ "tmp.zig:3:29: error: container 'builtin.Arch' has no member called 'x86'",
);
cases.add(
@@ -4274,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y: *void = @intToPtr(*void, x);
\\}
,
- ".tmp_source.zig:3:30: error: type '*void' has 0 bits and cannot store information",
+ "tmp.zig:3:30: error: type '*void' has 0 bits and cannot store information",
);
cases.add(
@@ -4284,7 +4312,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @fieldParentPtr(Foo, "a", a);
\\}
,
- ".tmp_source.zig:3:28: error: expected struct type, found 'i32'",
+ "tmp.zig:3:28: error: expected struct type, found 'i32'",
);
cases.add(
@@ -4296,7 +4324,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @fieldParentPtr(Foo, "a", a);
\\}
,
- ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'",
+ "tmp.zig:5:33: error: struct 'Foo' has no field 'a'",
);
cases.add(
@@ -4308,7 +4336,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @fieldParentPtr(Foo, "a", a);
\\}
,
- ".tmp_source.zig:5:38: error: expected pointer, found 'i32'",
+ "tmp.zig:5:38: error: expected pointer, found 'i32'",
);
cases.add(
@@ -4324,7 +4352,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
\\}
,
- ".tmp_source.zig:9:55: error: pointer value not based on parent struct",
+ "tmp.zig:9:55: error: pointer value not based on parent struct",
);
cases.add(
@@ -4339,7 +4367,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
\\}
,
- ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",
+ "tmp.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",
);
cases.add(
@@ -4349,7 +4377,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @byteOffsetOf(Foo, "a",);
\\}
,
- ".tmp_source.zig:3:26: error: expected struct type, found 'i32'",
+ "tmp.zig:3:26: error: expected struct type, found 'i32'",
);
cases.add(
@@ -4361,14 +4389,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @byteOffsetOf(Foo, "a",);
\\}
,
- ".tmp_source.zig:5:31: error: struct 'Foo' has no field 'a'",
+ "tmp.zig:5:31: error: struct 'Foo' has no field 'a'",
);
cases.addExe(
"missing main fn in executable",
\\
,
- "error: no member named 'main' in '",
+ "error: root source file has no member called 'main'",
);
cases.addExe(
@@ -4376,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn main() void {}
,
"error: 'main' is private",
- ".tmp_source.zig:1:1: note: declared here",
+ "tmp.zig:1:1: note: declared here",
);
cases.add(
@@ -4386,7 +4414,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return foo;
\\}
,
- ".tmp_source.zig:1:33: error: cannot set section of external variable 'foo'",
+ "tmp.zig:1:33: error: cannot set section of external variable 'foo'",
);
cases.add(
@@ -4396,7 +4424,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return foo;
\\}
,
- ".tmp_source.zig:2:30: error: cannot set section of local variable 'foo'",
+ "tmp.zig:2:30: error: cannot set section of local variable 'foo'",
);
cases.add(
@@ -4406,7 +4434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo();
\\}
,
- ".tmp_source.zig:1:29: error: cannot set section of external function 'foo'",
+ "tmp.zig:1:29: error: cannot set section of external function 'foo'",
);
cases.add(
@@ -4416,7 +4444,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return &a;
\\}
,
- ".tmp_source.zig:3:13: error: function returns address of local variable",
+ "tmp.zig:3:13: error: function returns address of local variable",
);
cases.add(
@@ -4427,7 +4455,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return if (c) &a else &b;
\\}
,
- ".tmp_source.zig:4:12: error: function returns address of local variable",
+ "tmp.zig:4:12: error: function returns address of local variable",
);
cases.add(
@@ -4452,8 +4480,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ if (!ok) unreachable;
\\}
,
- ".tmp_source.zig:9:17: error: redefinition of 'Self'",
- ".tmp_source.zig:5:9: note: previous definition is here",
+ "tmp.zig:9:17: error: redefinition of 'Self'",
+ "tmp.zig:5:9: note: previous definition is here",
);
cases.add(
@@ -4463,7 +4491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() ?i32 { return 1; }
,
- ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'",
+ "tmp.zig:2:15: error: expected type 'bool', found '?i32'",
);
cases.add(
@@ -4473,7 +4501,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() anyerror!i32 { return 1; }
,
- ".tmp_source.zig:2:15: error: expected type 'bool', found 'anyerror!i32'",
+ "tmp.zig:2:15: error: expected type 'bool', found 'anyerror!i32'",
);
cases.add(
@@ -4483,7 +4511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() bool { return true; }
,
- ".tmp_source.zig:2:15: error: expected optional type, found 'bool'",
+ "tmp.zig:2:15: error: expected optional type, found 'bool'",
);
cases.add(
@@ -4493,7 +4521,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() anyerror!i32 { return 1; }
,
- ".tmp_source.zig:2:15: error: expected optional type, found 'anyerror!i32'",
+ "tmp.zig:2:15: error: expected optional type, found 'anyerror!i32'",
);
cases.add(
@@ -4503,7 +4531,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() bool { return true; }
,
- ".tmp_source.zig:2:15: error: expected error union type, found 'bool'",
+ "tmp.zig:2:15: error: expected error union type, found 'bool'",
);
cases.add(
@@ -4513,7 +4541,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() ?i32 { return 1; }
,
- ".tmp_source.zig:2:15: error: expected error union type, found '?i32'",
+ "tmp.zig:2:15: error: expected error union type, found '?i32'",
);
cases.add(
@@ -4531,7 +4559,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\extern fn quux() void;
,
- ".tmp_source.zig:4:1: error: unable to inline function",
+ "tmp.zig:4:1: error: unable to inline function",
);
cases.add(
@@ -4542,7 +4570,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\inline fn bar() void { }
\\extern fn quux(usize) void;
,
- ".tmp_source.zig:4:1: error: unable to inline function",
+ "tmp.zig:4:1: error: unable to inline function",
);
cases.add(
@@ -4551,7 +4579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return a / b;
\\}
,
- ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",
+ "tmp.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",
);
cases.add(
@@ -4560,7 +4588,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return a % b;
\\}
,
- ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
+ "tmp.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
);
cases.add(
@@ -4571,7 +4599,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const c = a / b;
\\}
,
- ".tmp_source.zig:4:17: error: division by zero",
+ "tmp.zig:4:17: error: division by zero",
);
cases.add(
@@ -4582,7 +4610,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const c = a % b;
\\}
,
- ".tmp_source.zig:4:17: error: division by zero",
+ "tmp.zig:4:17: error: division by zero",
);
cases.add(
@@ -4592,8 +4620,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setRuntimeSafety(false);
\\}
,
- ".tmp_source.zig:3:5: error: runtime safety set twice for same scope",
- ".tmp_source.zig:2:5: note: first set here",
+ "tmp.zig:3:5: error: runtime safety set twice for same scope",
+ "tmp.zig:2:5: note: first set here",
);
cases.add(
@@ -4603,8 +4631,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setFloatMode(@import("builtin").FloatMode.Optimized);
\\}
,
- ".tmp_source.zig:3:5: error: float mode set twice for same scope",
- ".tmp_source.zig:2:5: note: first set here",
+ "tmp.zig:3:5: error: float mode set twice for same scope",
+ "tmp.zig:2:5: note: first set here",
);
cases.add(
@@ -4613,7 +4641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var b: u8[40] = undefined;
\\}
,
- ".tmp_source.zig:2:14: error: array access of non-array type 'type'",
+ "tmp.zig:2:14: error: array access of non-array type 'type'",
);
cases.add(
@@ -4626,7 +4654,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:4:13: error: cannot break out of defer expression",
+ "tmp.zig:4:13: error: cannot break out of defer expression",
);
cases.add(
@@ -4639,7 +4667,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:4:13: error: cannot continue out of defer expression",
+ "tmp.zig:4:13: error: cannot continue out of defer expression",
);
cases.add(
@@ -4653,7 +4681,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foos[0]();
\\}
,
- ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",
+ "tmp.zig:7:9: error: calling a generic function requires compile-time known function value",
);
cases.add(
@@ -4667,7 +4695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foos[0](true);
\\}
,
- ".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value",
+ "tmp.zig:7:9: error: calling a generic function requires compile-time known function value",
);
cases.add(
@@ -4681,24 +4709,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return bar;
\\}
,
- ".tmp_source.zig:1:13: error: aoeu",
- ".tmp_source.zig:3:19: note: referenced here",
- ".tmp_source.zig:7:12: note: referenced here",
- );
-
- cases.add(
- "instantiating an undefined value for an invalid struct that contains itself",
- \\const Foo = struct {
- \\ x: Foo,
- \\};
- \\
- \\var foo: Foo = undefined;
- \\
- \\export fn entry() usize {
- \\ return @sizeOf(@typeOf(foo.x));
- \\}
- ,
- ".tmp_source.zig:1:13: error: struct 'Foo' contains itself",
+ "tmp.zig:1:13: error: aoeu",
+ "tmp.zig:3:19: note: referenced here",
+ "tmp.zig:7:12: note: referenced here",
);
cases.add(
@@ -4707,7 +4720,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = 0x1.0p16384;
\\}
,
- ".tmp_source.zig:2:15: error: float literal out of range of any type",
+ "tmp.zig:2:15: error: float literal out of range of any type",
);
cases.add(
@@ -4716,7 +4729,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = 0x1.0p-16384;
\\}
,
- ".tmp_source.zig:2:15: error: float literal out of range of any type",
+ "tmp.zig:2:15: error: float literal out of range of any type",
);
cases.add(
@@ -4725,7 +4738,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return i32(12.34);
\\}
,
- ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",
+ "tmp.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",
);
cases.add(
@@ -4734,7 +4747,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @ptrToInt(x);
\\}
,
- ".tmp_source.zig:2:22: error: expected pointer, found 'i32'",
+ "tmp.zig:2:22: error: expected pointer, found 'i32'",
);
cases.add(
@@ -4743,7 +4756,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @shlExact(u8(0b01010101), 2);
\\}
,
- ".tmp_source.zig:2:15: error: operation caused overflow",
+ "tmp.zig:2:15: error: operation caused overflow",
);
cases.add(
@@ -4752,7 +4765,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @shrExact(u8(0b10101010), 2);
\\}
,
- ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits",
+ "tmp.zig:2:15: error: exact shift shifted out 1 bits",
);
cases.add(
@@ -4761,7 +4774,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 0x11 << x;
\\}
,
- ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known",
+ "tmp.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known",
);
cases.add(
@@ -4770,7 +4783,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x << y;
\\}
,
- ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'",
+ "tmp.zig:2:17: error: expected type 'u3', found 'u8'",
);
cases.add(
@@ -4780,7 +4793,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a: u16 = 300;
\\}
,
- ".tmp_source.zig:1:1: error: declaration shadows primitive type 'u16'",
+ "tmp.zig:1:1: error: declaration shadows primitive type 'u16'",
);
cases.add(
@@ -4799,7 +4812,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ x.* += 1;
\\}
,
- ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'",
+ "tmp.zig:8:13: error: expected type '*u32', found '*align(1) u32'",
);
cases.add(
@@ -4819,9 +4832,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ x[0] += 1;
\\}
,
- ".tmp_source.zig:9:18: error: cast increases pointer alignment",
- ".tmp_source.zig:9:23: note: '*align(1) u32' has alignment 1",
- ".tmp_source.zig:9:18: note: '*[1]u32' has alignment 4",
+ "tmp.zig:9:18: error: cast increases pointer alignment",
+ "tmp.zig:9:23: note: '*align(1) u32' has alignment 1",
+ "tmp.zig:9:18: note: '*[1]u32' has alignment 4",
);
cases.add(
@@ -4832,9 +4845,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return ptr.*;
\\}
,
- ".tmp_source.zig:3:17: error: cast increases pointer alignment",
- ".tmp_source.zig:3:38: note: '*u8' has alignment 1",
- ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
+ "tmp.zig:3:17: error: cast increases pointer alignment",
+ "tmp.zig:3:38: note: '*u8' has alignment 1",
+ "tmp.zig:3:26: note: '*u32' has alignment 4",
);
cases.add(
@@ -4843,7 +4856,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @alignCast(4, u32(3));
\\}
,
- ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'",
+ "tmp.zig:2:22: error: expected pointer or slice, found 'u32'",
);
cases.add(
@@ -4856,7 +4869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn alignedSmall() align(4) i32 { return 1234; }
,
- ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",
+ "tmp.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",
);
cases.add(
@@ -4868,7 +4881,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x == 5678;
\\}
,
- ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'",
+ "tmp.zig:4:32: error: expected type '*i32', found '*align(1) i32'",
);
cases.add(
@@ -4877,7 +4890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const array = [2]u8{1, 2, 3};
\\}
,
- ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",
+ "tmp.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",
);
cases.add(
@@ -4889,7 +4902,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ bar(@ptrCast(*c_void, &x));
\\}
,
- ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'",
+ "tmp.zig:5:9: error: expected type '*Derp', found '*c_void'",
);
cases.add(
@@ -4906,7 +4919,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var d = null;
\\ var e = opaque.*;
\\ var f = i32;
- \\ var g = @import("std",);
\\ var h = (Foo {}).bar;
\\
\\ var z: noreturn = return;
@@ -4916,16 +4928,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ fn bar(self: *const Foo) void {}
\\};
,
- ".tmp_source.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
- ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
- ".tmp_source.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
- ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
- ".tmp_source.zig:10:4: error: variable of type '(null)' must be const or comptime",
- ".tmp_source.zig:11:4: error: variable of type 'Opaque' not allowed",
- ".tmp_source.zig:12:4: error: variable of type 'type' must be const or comptime",
- ".tmp_source.zig:13:4: error: variable of type '(namespace)' must be const or comptime",
- ".tmp_source.zig:14:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
- ".tmp_source.zig:16:4: error: unreachable code",
+ "tmp.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
+ "tmp.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
+ "tmp.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
+ "tmp.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
+ "tmp.zig:10:4: error: variable of type '(null)' must be const or comptime",
+ "tmp.zig:11:4: error: variable of type 'Opaque' not allowed",
+ "tmp.zig:12:4: error: variable of type 'type' must be const or comptime",
+ "tmp.zig:13:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
+ "tmp.zig:15:4: error: unreachable code",
);
cases.add(
@@ -4935,7 +4946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {}
\\}
,
- ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'",
+ "tmp.zig:3:50: error: expected type 'builtin.AtomicOrder', found 'u32'",
);
cases.add(
@@ -4945,7 +4956,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @export("entry", entry, u32(1234));
\\}
,
- ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'",
+ "tmp.zig:3:32: error: expected type 'builtin.GlobalLinkage', found 'u32'",
);
cases.add(
@@ -4974,7 +4985,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\}
,
- ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
+ "tmp.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
);
cases.add(
@@ -4983,7 +4994,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setAlignStack(16);
\\}
,
- ".tmp_source.zig:2:5: error: @setAlignStack outside function",
+ "tmp.zig:2:5: error: @setAlignStack outside function",
);
cases.add(
@@ -4992,7 +5003,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setAlignStack(16);
\\}
,
- ".tmp_source.zig:2:5: error: @setAlignStack in naked function",
+ "tmp.zig:2:5: error: @setAlignStack in naked function",
);
cases.add(
@@ -5004,7 +5015,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setAlignStack(16);
\\}
,
- ".tmp_source.zig:5:5: error: @setAlignStack in inline function",
+ "tmp.zig:5:5: error: @setAlignStack in inline function",
);
cases.add(
@@ -5014,8 +5025,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setAlignStack(16);
\\}
,
- ".tmp_source.zig:3:5: error: alignstack set twice",
- ".tmp_source.zig:2:5: note: first set here",
+ "tmp.zig:3:5: error: alignstack set twice",
+ "tmp.zig:2:5: note: first set here",
);
cases.add(
@@ -5024,7 +5035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @setAlignStack(511 + 1);
\\}
,
- ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",
+ "tmp.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",
);
cases.add(
@@ -5071,7 +5082,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable",
+ "tmp.zig:37:16: error: cannot store runtime value in compile time variable",
);
cases.add(
@@ -5087,7 +5098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return x.blah;
\\}
,
- ".tmp_source.zig:9:13: error: type '*MyType' does not support field access",
+ "tmp.zig:9:13: error: type '*MyType' does not support field access",
);
cases.add(
@@ -5095,7 +5106,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"fn test() bool {\r\n" ++
" true\r\n" ++
"}\r\n",
- ".tmp_source.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported",
+ "tmp.zig:1:17: error: invalid carriage return, only '\\n' line endings are supported",
);
cases.add(
@@ -5105,7 +5116,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ true\r
\\}
,
- ".tmp_source.zig:1:1: error: invalid character: '\\xff'",
+ "tmp.zig:1:1: error: invalid character: '\\xff'",
);
cases.add(
@@ -5113,7 +5124,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"fn test() bool {\n" ++
"\ttrue\n" ++
"}\n",
- ".tmp_source.zig:2:1: error: invalid character: '\\t'",
+ "tmp.zig:2:1: error: invalid character: '\\t'",
);
cases.add(
@@ -5122,7 +5133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @ArgType(i32, 3);
\\}
,
- ".tmp_source.zig:2:18: error: expected function, found 'i32'",
+ "tmp.zig:2:18: error: expected function, found 'i32'",
);
cases.add(
@@ -5132,7 +5143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn add(a: i32, b: i32) i32 { return a + b; }
,
- ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments",
+ "tmp.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments",
);
cases.add(
@@ -5141,7 +5152,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @memberType(i32, 0);
\\}
,
- ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType",
+ "tmp.zig:2:21: error: type 'i32' does not support @memberType",
);
cases.add(
@@ -5151,7 +5162,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = enum {A,};
,
- ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType",
+ "tmp.zig:2:21: error: type 'Foo' does not support @memberType",
);
cases.add(
@@ -5161,7 +5172,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = struct {};
,
- ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
+ "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
);
cases.add(
@@ -5171,7 +5182,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = union {A: void,};
,
- ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
+ "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
);
cases.add(
@@ -5180,7 +5191,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @memberName(i32, 0);
\\}
,
- ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName",
+ "tmp.zig:2:21: error: type 'i32' does not support @memberName",
);
cases.add(
@@ -5190,7 +5201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = struct {};
,
- ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
+ "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members",
);
cases.add(
@@ -5200,7 +5211,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = enum {A,};
,
- ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
+ "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
);
cases.add(
@@ -5210,7 +5221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\const Foo = union {A:i32,};
,
- ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
+ "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members",
);
cases.add(
@@ -5220,7 +5231,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\pub extern fn foo(format: *const u8, ...) void;
,
- ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'",
+ "tmp.zig:2:9: error: expected type '*const u8', found '[5]u8'",
);
cases.add(
@@ -5239,9 +5250,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var allocator: ContextAllocator = undefined;
\\}
,
- ".tmp_source.zig:4:25: error: aoeu",
- ".tmp_source.zig:1:36: note: called from here",
- ".tmp_source.zig:12:20: note: referenced here",
+ "tmp.zig:4:25: error: aoeu",
+ "tmp.zig:1:36: note: called from here",
+ "tmp.zig:12:20: note: referenced here",
);
cases.add(
@@ -5258,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = Small.One;
\\}
,
- ".tmp_source.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'",
+ "tmp.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'",
);
cases.add(
@@ -5273,7 +5284,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = Small.One;
\\}
,
- ".tmp_source.zig:1:21: error: expected integer, found 'f32'",
+ "tmp.zig:1:21: error: expected integer, found 'f32'",
);
cases.add(
@@ -5289,7 +5300,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: u2 = Small.Two;
\\}
,
- ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",
+ "tmp.zig:9:22: error: expected type 'u2', found 'Small'",
);
cases.add(
@@ -5306,7 +5317,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = @intToEnum(Small, y);
\\}
,
- ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'",
+ "tmp.zig:10:31: error: expected type 'u2', found 'u3'",
);
cases.add(
@@ -5322,7 +5333,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y = Small.Two;
\\}
,
- ".tmp_source.zig:1:20: error: expected unsigned integer, found 'i2'",
+ "tmp.zig:1:20: error: expected unsigned integer, found 'i2'",
);
cases.add(
@@ -5334,7 +5345,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: MultipleChoice = undefined;
\\}
,
- ".tmp_source.zig:2:14: error: enums, not structs, support field assignment",
+ "tmp.zig:2:14: error: enums, not structs, support field assignment",
);
cases.add(
@@ -5346,8 +5357,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: MultipleChoice = undefined;
\\}
,
- ".tmp_source.zig:2:14: error: non-enum union field assignment",
- ".tmp_source.zig:1:24: note: consider 'union(enum)' here",
+ "tmp.zig:2:14: error: non-enum union field assignment",
+ "tmp.zig:1:24: note: consider 'union(enum)' here",
);
cases.add(
@@ -5357,7 +5368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @sizeOf(Foo);
\\}
,
- ".tmp_source.zig:1:13: error: enums must have 1 or more fields",
+ "tmp.zig:1:13: error: enums must have 1 or more fields",
);
cases.add(
@@ -5367,7 +5378,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @sizeOf(Foo);
\\}
,
- ".tmp_source.zig:1:13: error: unions must have 1 or more fields",
+ "tmp.zig:1:13: error: unions must have 1 or more fields",
);
cases.add(
@@ -5383,8 +5394,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = MultipleChoice.C;
\\}
,
- ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
- ".tmp_source.zig:4:9: note: other occurrence here",
+ "tmp.zig:6:9: error: enum tag value 60 already taken",
+ "tmp.zig:4:9: note: other occurrence here",
);
cases.add(
@@ -5402,8 +5413,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return @sizeOf(Payload);
\\}
,
- ".tmp_source.zig:6:17: error: enum field missing: 'C'",
- ".tmp_source.zig:4:5: note: declared here",
+ "tmp.zig:6:17: error: enum field missing: 'C'",
+ "tmp.zig:4:5: note: declared here",
);
cases.add(
@@ -5415,8 +5426,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @TagType(Foo);
\\}
,
- ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
- ".tmp_source.zig:1:13: note: consider 'union(enum)' here",
+ "tmp.zig:5:24: error: union 'Foo' has no tag",
+ "tmp.zig:1:13: note: consider 'union(enum)' here",
);
cases.add(
@@ -5428,7 +5439,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @TagType(Foo);
\\}
,
- ".tmp_source.zig:1:24: error: expected integer tag type, found 'f32'",
+ "tmp.zig:1:24: error: expected integer tag type, found 'f32'",
);
cases.add(
@@ -5440,7 +5451,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const x = @TagType(Foo);
\\}
,
- ".tmp_source.zig:1:19: error: expected enum tag type, found 'u32'",
+ "tmp.zig:1:19: error: expected enum tag type, found 'u32'",
);
cases.add(
@@ -5456,8 +5467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = MultipleChoice { .C = {} };
\\}
,
- ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
- ".tmp_source.zig:4:9: note: other occurrence here",
+ "tmp.zig:6:9: error: enum tag value 60 already taken",
+ "tmp.zig:4:9: note: other occurrence here",
);
cases.add(
@@ -5477,8 +5488,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = Payload {.A = 1234};
\\}
,
- ".tmp_source.zig:10:5: error: enum field not found: 'D'",
- ".tmp_source.zig:1:16: note: enum declared here",
+ "tmp.zig:10:5: error: enum field not found: 'D'",
+ "tmp.zig:1:16: note: enum declared here",
);
cases.add(
@@ -5492,8 +5503,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var b = Letter.B;
\\}
,
- ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",
- ".tmp_source.zig:1:16: note: consider 'union(enum)' here",
+ "tmp.zig:2:8: error: structs and unions, not enums, support field types",
+ "tmp.zig:1:16: note: consider 'union(enum)' here",
);
cases.add(
@@ -5505,7 +5516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = Letter { .A = {} };
\\}
,
- ".tmp_source.zig:2:5: error: struct field missing type",
+ "tmp.zig:2:5: error: struct field missing type",
);
cases.add(
@@ -5517,7 +5528,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = Letter { .A = {} };
\\}
,
- ".tmp_source.zig:2:5: error: union field missing type",
+ "tmp.zig:2:5: error: union field missing type",
);
cases.add(
@@ -5536,7 +5547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = Payload { .A = 1234 };
\\}
,
- ".tmp_source.zig:6:30: error: extern union does not support enum tag type",
+ "tmp.zig:6:30: error: extern union does not support enum tag type",
);
cases.add(
@@ -5555,7 +5566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var a = Payload { .A = 1234 };
\\}
,
- ".tmp_source.zig:6:30: error: packed union does not support enum tag type",
+ "tmp.zig:6:30: error: packed union does not support enum tag type",
);
cases.add(
@@ -5576,8 +5587,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
,
- ".tmp_source.zig:11:14: error: switch on union which has no attached enum",
- ".tmp_source.zig:1:17: note: consider 'union(enum)' here",
+ "tmp.zig:11:14: error: switch on union which has no attached enum",
+ "tmp.zig:1:17: note: consider 'union(enum)' here",
);
cases.add(
@@ -5590,8 +5601,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = @intToEnum(Foo, 0);
\\}
,
- ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
- ".tmp_source.zig:1:13: note: 'Foo' declared here",
+ "tmp.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
+ "tmp.zig:1:13: note: 'Foo' declared here",
);
cases.add(
@@ -5606,8 +5617,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: Value = Letter.A;
\\}
,
- ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
- ".tmp_source.zig:3:5: note: field 'A' declared here",
+ "tmp.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
+ "tmp.zig:3:5: note: field 'A' declared here",
);
cases.add(
@@ -5625,8 +5636,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x: Value = l;
\\}
,
- ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
- ".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
+ "tmp.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
+ "tmp.zig:3:5: note: field 'A' has type 'i32'",
);
cases.add(
@@ -5638,7 +5649,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const fieldOffset = @byteOffsetOf(Empty, "val",);
\\}
,
- ".tmp_source.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",
+ "tmp.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",
);
cases.add(
@@ -5650,7 +5661,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const fieldOffset = @bitOffsetOf(Empty, "val",);
\\}
,
- ".tmp_source.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
+ "tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
);
cases.add(
@@ -5664,7 +5675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const bar_val = foo.Bar;
\\}
,
- ".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
+ "tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
);
cases.add(
@@ -5674,7 +5685,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @typeOf(generic).ReturnType;
\\}
,
- ".tmp_source.zig:3:25: error: ReturnType has not been resolved because 'fn(var)var' is generic",
+ "tmp.zig:3:25: error: ReturnType has not been resolved because 'fn(var)var' is generic",
);
cases.add(
@@ -5684,7 +5695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @ArgType(@typeOf(generic), 0);
\\}
,
- ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
+ "tmp.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
);
cases.add(
@@ -5694,7 +5705,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ asm volatile ("" : [baz]"+r"(bar) : : "");
\\}
,
- ".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",
+ "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",
);
cases.add(
@@ -5703,7 +5714,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ asm volatile ("" : : [bar]"r"(3) : "");
\\}
,
- ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int",
+ "tmp.zig:2:35: error: expected sized integer or sized float, found comptime_int",
);
cases.add(
@@ -5712,7 +5723,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ asm volatile ("" : : [bar]"r"(3.17) : "");
\\}
,
- ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float",
+ "tmp.zig:2:35: error: expected sized integer or sized float, found comptime_float",
);
cases.add(
@@ -5726,7 +5737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const foo = Foo { .Bar = x, .Baz = u8 };
\\}
,
- ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
+ "tmp.zig:7:30: error: unable to evaluate constant expression",
);
cases.add(
@@ -5740,7 +5751,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const foo = Foo { .Bar = x };
\\}
,
- ".tmp_source.zig:7:30: error: unable to evaluate constant expression",
+ "tmp.zig:7:30: error: unable to evaluate constant expression",
);
cases.addTest(
@@ -5750,7 +5761,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var v: V = undefined;
\\}
,
- ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
+ "tmp.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
);
cases.add("compileLog of tagged enum doesn't crash the compiler",
@@ -5765,5 +5776,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\pub fn main () void {
\\ comptime testCompileLog(Bar{.X = 123});
\\}
- , ".tmp_source.zig:6:5: error: found compile log statement");
+ , "tmp.zig:6:5: error: found compile log statement");
}
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
index d1286cbf8a961af01717a59dd8cb35072629c4b2..9940a76af11c1801852bda86e43587ec59bd68f4 100644
--- a/test/stage1/behavior.zig
+++ b/test/stage1/behavior.zig
@@ -18,6 +18,7 @@ comptime {
_ = @import("behavior/bugs/1421.zig");
_ = @import("behavior/bugs/1442.zig");
_ = @import("behavior/bugs/1486.zig");
+ _ = @import("behavior/bugs/1500.zig");
_ = @import("behavior/bugs/1851.zig");
_ = @import("behavior/bugs/2006.zig");
_ = @import("behavior/bugs/394.zig");
@@ -25,6 +26,7 @@ comptime {
_ = @import("behavior/bugs/529.zig");
_ = @import("behavior/bugs/655.zig");
_ = @import("behavior/bugs/656.zig");
+ _ = @import("behavior/bugs/679.zig");
_ = @import("behavior/bugs/704.zig");
_ = @import("behavior/bugs/718.zig");
_ = @import("behavior/bugs/726.zig");
@@ -54,14 +56,14 @@ comptime {
_ = @import("behavior/math.zig");
_ = @import("behavior/merge_error_sets.zig");
_ = @import("behavior/misc.zig");
- _ = @import("behavior/namespace_depends_on_compile_var/index.zig");
+ _ = @import("behavior/namespace_depends_on_compile_var.zig");
_ = @import("behavior/new_stack_call.zig");
_ = @import("behavior/null.zig");
_ = @import("behavior/optional.zig");
_ = @import("behavior/pointers.zig");
_ = @import("behavior/popcount.zig");
_ = @import("behavior/ptrcast.zig");
- _ = @import("behavior/pub_enum/index.zig");
+ _ = @import("behavior/pub_enum.zig");
_ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
_ = @import("behavior/reflection.zig");
_ = @import("behavior/sizeof_and_typeof.zig");
@@ -78,6 +80,7 @@ comptime {
_ = @import("behavior/truncate.zig");
_ = @import("behavior/try.zig");
_ = @import("behavior/type_info.zig");
+ _ = @import("behavior/typename.zig");
_ = @import("behavior/undefined.zig");
_ = @import("behavior/underscore.zig");
_ = @import("behavior/union.zig");
diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig
index 845d80777aae7fa5478841a3de2e77751d3c8cfc..414fa42e1ea6c6187e953cf15122aba336bca375 100644
--- a/test/stage1/behavior/asm.zig
+++ b/test/stage1/behavior/asm.zig
@@ -4,16 +4,16 @@ const expect = @import("std").testing.expect;
comptime {
if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
asm volatile (
- \\.globl aoeu;
- \\.type aoeu, @function;
- \\.set aoeu, derp;
+ \\.globl this_is_my_alias;
+ \\.type this_is_my_alias, @function;
+ \\.set this_is_my_alias, derp;
);
}
}
test "module level assembly" {
if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
- expect(aoeu() == 1234);
+ expect(this_is_my_alias() == 1234);
}
}
@@ -85,7 +85,7 @@ test "sized integer/float in asm input" {
);
}
-extern fn aoeu() i32;
+extern fn this_is_my_alias() i32;
export fn derp() i32 {
return 1234;
diff --git a/test/stage1/behavior/bugs/1500.zig b/test/stage1/behavior/bugs/1500.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e24cfe5a9ce648c9b9cfcccccb1070ebac29b469
--- /dev/null
+++ b/test/stage1/behavior/bugs/1500.zig
@@ -0,0 +1,10 @@
+const A = struct {
+ b: B,
+};
+
+const B = fn (A) void;
+
+test "allow these dependencies" {
+ var a: A = undefined;
+ var b: B = undefined;
+}
diff --git a/test/stage1/behavior/bugs/679.zig b/test/stage1/behavior/bugs/679.zig
new file mode 100644
index 0000000000000000000000000000000000000000..20b2b7b02abbb249dd9ed3cf309ff0148ef672d5
--- /dev/null
+++ b/test/stage1/behavior/bugs/679.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+pub fn List(comptime T: type) type {
+ return u32;
+}
+
+const ElementList = List(Element);
+const Element = struct {
+ link: ElementList,
+};
+
+test "false dependency loop in struct definition" {
+ const listType = ElementList;
+ var x: listType = 42;
+ expect(x == 42);
+}
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index 91cab78bc72219d98588ddfcdaffc26632ddd759..a2d752457c50bd041d9ce54f7be0a7a5ac83f5d0 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
+const expectEqualSlices = std.testing.expectEqualSlices;
const mem = std.mem;
const cstr = std.cstr;
const builtin = @import("builtin");
@@ -469,7 +470,7 @@ test "@typeId" {
expect(@typeId(AUnionEnum) == Tid.Union);
expect(@typeId(AUnion) == Tid.Union);
expect(@typeId(fn () void) == Tid.Fn);
- expect(@typeId(@typeOf(builtin)) == Tid.Namespace);
+ expect(@typeId(@typeOf(builtin)) == Tid.Type);
// TODO bound fn
// TODO arg tuple
// TODO opaque
@@ -488,7 +489,7 @@ test "@typeName" {
expect(mem.eql(u8, @typeName(i64), "i64"));
expect(mem.eql(u8, @typeName(*usize), "*usize"));
// https://github.com/ziglang/zig/issues/675
- expect(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
+ expectEqualSlices(u8, "behavior.misc.TypeFromFn(u8)", @typeName(TypeFromFn(u8)));
expect(mem.eql(u8, @typeName(Struct), "Struct"));
expect(mem.eql(u8, @typeName(Union), "Union"));
expect(mem.eql(u8, @typeName(Enum), "Enum"));
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var.zig b/test/stage1/behavior/namespace_depends_on_compile_var.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4c4fc4eefea30ac89f75d7d070e927a5ea425b9e
--- /dev/null
+++ b/test/stage1/behavior/namespace_depends_on_compile_var.zig
@@ -0,0 +1,14 @@
+const builtin = @import("builtin");
+const expect = @import("std").testing.expect;
+
+test "namespace depends on compile var" {
+ if (some_namespace.a_bool) {
+ expect(some_namespace.a_bool);
+ } else {
+ expect(!some_namespace.a_bool);
+ }
+}
+const some_namespace = switch (builtin.os) {
+ builtin.Os.linux => @import("namespace_depends_on_compile_var/a.zig"),
+ else => @import("namespace_depends_on_compile_var/b.zig"),
+};
diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
deleted file mode 100644
index 32feaced1030101d6517e41278f04376bf94ecf2..0000000000000000000000000000000000000000
--- a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
+++ /dev/null
@@ -1,14 +0,0 @@
-const builtin = @import("builtin");
-const expect = @import("std").testing.expect;
-
-test "namespace depends on compile var" {
- if (some_namespace.a_bool) {
- expect(some_namespace.a_bool);
- } else {
- expect(!some_namespace.a_bool);
- }
-}
-const some_namespace = switch (builtin.os) {
- builtin.Os.linux => @import("a.zig"),
- else => @import("b.zig"),
-};
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
index eed7a765d7230c7e6c895d17d774c925de767eb1..1bb23866b4d794f5d71d07e5e61f0947a88a600d 100644
--- a/test/stage1/behavior/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -124,3 +124,9 @@ test "implicit cast error unions with non-optional to optional pointer" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "initialize const optional C pointer to null" {
+ const a: ?[*c]i32 = null;
+ expect(a == null);
+ comptime expect(a == null);
+}
diff --git a/test/stage1/behavior/pub_enum.zig b/test/stage1/behavior/pub_enum.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6275be7a0190204d60129926f26add2c4f2b3347
--- /dev/null
+++ b/test/stage1/behavior/pub_enum.zig
@@ -0,0 +1,13 @@
+const other = @import("pub_enum/other.zig");
+const expect = @import("std").testing.expect;
+
+test "pub enum" {
+ pubEnumTest(other.APubEnum.Two);
+}
+fn pubEnumTest(foo: other.APubEnum) void {
+ expect(foo == other.APubEnum.Two);
+}
+
+test "cast with imported symbol" {
+ expect(other.size_t(42) == 42);
+}
diff --git a/test/stage1/behavior/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig
deleted file mode 100644
index 15e4114c2d1f1b3d08c36003ebc2287cd4f73e89..0000000000000000000000000000000000000000
--- a/test/stage1/behavior/pub_enum/index.zig
+++ /dev/null
@@ -1,13 +0,0 @@
-const other = @import("other.zig");
-const expect = @import("std").testing.expect;
-
-test "pub enum" {
- pubEnumTest(other.APubEnum.Two);
-}
-fn pubEnumTest(foo: other.APubEnum) void {
- expect(foo == other.APubEnum.Two);
-}
-
-test "cast with imported symbol" {
- expect(other.size_t(42) == 42);
-}
diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig
index 13fa84d0fa395265404f7ef7bdf5eb3fbaab4285..19eb570150d829f6915a73bbb8d1dab4a09f477c 100644
--- a/test/stage1/behavior/slice.zig
+++ b/test/stage1/behavior/slice.zig
@@ -1,5 +1,7 @@
-const expect = @import("std").testing.expect;
-const mem = @import("std").mem;
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqualSlices = std.testing.expectEqualSlices;
+const mem = std.mem;
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
const y = x[0x100..];
@@ -38,3 +40,10 @@ test "implicitly cast array of size 0 to slice" {
fn assertLenIsZero(msg: []const u8) void {
expect(msg.len == 0);
}
+
+test "C pointer" {
+ var buf: [*c]const u8 = c"kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
+ var len: u32 = 10;
+ var slice = buf[0..len];
+ expectEqualSlices(u8, "kjdhfkjdhf", slice);
+}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index dc185cc96038650ef5f0e29a8fdb4f82717c80a9..510a56f619389c26873bbf08319c77f744c04962 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -186,7 +186,7 @@ fn testUnion() void {
expect(TypeId(typeinfo_info) == TypeId.Union);
expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
expect(typeinfo_info.Union.tag_type.? == TypeId);
- expect(typeinfo_info.Union.fields.len == 25);
+ expect(typeinfo_info.Union.fields.len == 24);
expect(typeinfo_info.Union.fields[4].enum_field != null);
expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
diff --git a/test/stage1/behavior/typename.zig b/test/stage1/behavior/typename.zig
new file mode 100644
index 0000000000000000000000000000000000000000..1abefe5b5e7bdb22ac7023740a48f4c09fe1d1f1
--- /dev/null
+++ b/test/stage1/behavior/typename.zig
@@ -0,0 +1,7 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const expectEqualSlices = std.testing.expectEqualSlices;
+
+test "slice" {
+ expectEqualSlices(u8, "[]u8", @typeName([]u8));
+}
diff --git a/test/standalone/main_pkg_path/a/test.zig b/test/standalone/main_pkg_path/a/test.zig
new file mode 100644
index 0000000000000000000000000000000000000000..286489912b392f4e891fddef0b3e91e9ce27eb41
--- /dev/null
+++ b/test/standalone/main_pkg_path/a/test.zig
@@ -0,0 +1,5 @@
+const b = @import("../b.zig");
+
+test "main pkg path" {
+ b.foo();
+}
diff --git a/test/standalone/main_pkg_path/b.zig b/test/standalone/main_pkg_path/b.zig
new file mode 100644
index 0000000000000000000000000000000000000000..87d61fa63e887512abddd3a1c64891c53cf95595
--- /dev/null
+++ b/test/standalone/main_pkg_path/b.zig
@@ -0,0 +1 @@
+pub fn foo() void {}
diff --git a/test/standalone/main_pkg_path/build.zig b/test/standalone/main_pkg_path/build.zig
new file mode 100644
index 0000000000000000000000000000000000000000..c4ac18f967b3ffd5b904bc5d05d86bfc579939dc
--- /dev/null
+++ b/test/standalone/main_pkg_path/build.zig
@@ -0,0 +1,9 @@
+const Builder = @import("std").build.Builder;
+
+pub fn build(b: *Builder) void {
+ const test_exe = b.addTest("a/test.zig");
+ test_exe.setMainPkgPath(".");
+
+ const test_step = b.step("test", "Test the program");
+ test_step.dependOn(&test_exe.step);
+}
diff --git a/test/standalone/static_c_lib/build.zig b/test/standalone/static_c_lib/build.zig
new file mode 100644
index 0000000000000000000000000000000000000000..afbb63c6bf722371f5add5761889ed6645230164
--- /dev/null
+++ b/test/standalone/static_c_lib/build.zig
@@ -0,0 +1,18 @@
+const Builder = @import("std").build.Builder;
+
+pub fn build(b: *Builder) void {
+ const mode = b.standardReleaseOptions();
+
+ const foo = b.addStaticLibrary("foo", null);
+ foo.addCSourceFile("foo.c", [][]const u8{});
+ foo.setBuildMode(mode);
+ foo.addIncludeDir(".");
+
+ const test_exe = b.addTest("foo.zig");
+ test_exe.setBuildMode(mode);
+ test_exe.linkLibrary(foo);
+ test_exe.addIncludeDir(".");
+
+ const test_step = b.step("test", "Test it");
+ test_step.dependOn(&test_exe.step);
+}
diff --git a/test/standalone/static_c_lib/foo.c b/test/standalone/static_c_lib/foo.c
new file mode 100644
index 0000000000000000000000000000000000000000..2366282d47e315c971de79608ec86645a19da170
--- /dev/null
+++ b/test/standalone/static_c_lib/foo.c
@@ -0,0 +1,4 @@
+#include "foo.h"
+uint32_t add(uint32_t a, uint32_t b) {
+ return a + b;
+}
diff --git a/test/standalone/static_c_lib/foo.h b/test/standalone/static_c_lib/foo.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8ebb9842e6f165bffb4e78fd189be8dbea5feda
--- /dev/null
+++ b/test/standalone/static_c_lib/foo.h
@@ -0,0 +1,2 @@
+#include
+uint32_t add(uint32_t a, uint32_t b);
diff --git a/test/standalone/static_c_lib/foo.zig b/test/standalone/static_c_lib/foo.zig
new file mode 100644
index 0000000000000000000000000000000000000000..edf94539c82a102f57656f817929ca6d841ae969
--- /dev/null
+++ b/test/standalone/static_c_lib/foo.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const c = @cImport(@cInclude("foo.h"));
+
+test "C add" {
+ const result = c.add(1, 2);
+ expect(result == 3);
+}
diff --git a/test/tests.zig b/test/tests.zig
index 582736e8d5566b3d42a1a3e12b92723a575fc622..d3a27f3e94ee834cd2bb37de36ed038d99c7820a 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -569,7 +569,7 @@ pub const CompileErrorContext = struct {
const ErrLineIter = struct {
lines: mem.SplitIterator,
- const source_file = ".tmp_source.zig";
+ const source_file = "tmp.zig";
fn init(input: []const u8) ErrLineIter {
return ErrLineIter{ .lines = mem.separate(input, "\n") };
@@ -759,7 +759,7 @@ pub const CompileErrorContext = struct {
.is_test = false,
};
- tc.addSourceFile(".tmp_source.zig", source);
+ tc.addSourceFile("tmp.zig", source);
comptime var arg_i = 0;
inline while (arg_i < expected_lines.len) : (arg_i += 1) {
tc.addExpectedError(expected_lines[arg_i]);
@@ -980,15 +980,18 @@ pub const TranslateCContext = struct {
Term.Exited => |code| {
if (code != 0) {
warn("Compilation failed with exit code {}\n", code);
+ printInvocation(zig_args.toSliceConst());
return error.TestFailed;
}
},
Term.Signal => |code| {
warn("Compilation failed with signal {}\n", code);
+ printInvocation(zig_args.toSliceConst());
return error.TestFailed;
},
else => {
warn("Compilation terminated unexpectedly\n");
+ printInvocation(zig_args.toSliceConst());
return error.TestFailed;
},
}