From 0f7de58b642539ad6a71368940f43f59a41e71b2 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Mon, 26 Nov 2018 01:09:12 +0900 Subject: [PATCH 001/218] std.mem: add new separate method and rework SplitIterator; --- std/mem.zig | 104 +++++++++++++++++++++++++++++++++++++++++++----- std/os/path.zig | 14 ++++--- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index 005d88791f..adb8b05956 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -607,11 +607,15 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { /// any of the bytes in `split_bytes`. /// split(" abc def ghi ", " ") /// Will return slices for "abc", "def", "ghi", null, in that order. +/// If `split_bytes` does not exist in buffer, +/// the iterator will return `buffer`, null, in that order. pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { return SplitIterator{ .index = 0, .buffer = buffer, .split_bytes = split_bytes, + .glob = true, + .spun = false, }; } @@ -621,6 +625,76 @@ test "mem.split" { assert(eql(u8, it.next().?, "def")); assert(eql(u8, it.next().?, "ghi")); assert(it.next() == null); + + it = split("..\\bob", "\\"); + assert(eql(u8, it.next().?, "..")); + assert(eql(u8, "..", "..\\bob"[0..it.index])); + assert(eql(u8, it.next().?, "bob")); + assert(it.next() == null); + + it = split("//a/b", "/"); + assert(eql(u8, it.next().?, "a")); + assert(eql(u8, it.next().?, "b")); + assert(eql(u8, "//a/b", "//a/b"[0..it.index])); + assert(it.next() == null); + + it = split("|", "|"); + assert(it.next() == null); + + it = split("", "|"); + assert(eql(u8, it.next().?, "")); + assert(it.next() == null); + + it = split("hello", ""); + assert(eql(u8, it.next().?, "hello")); + assert(it.next() == null); + + it = split("hello", " "); + assert(eql(u8, it.next().?, "hello")); + assert(it.next() == null); +} + +/// Returns an iterator that iterates over the slices of `buffer` that +/// seperates by bytes in `delimiter`. +/// separate("abc|def||ghi", "|") +/// Will return slices for "abc", "def", "", "ghi", null, in that order. +/// If `delimiter` does not exist in buffer, +/// the iterator will return `buffer`, null, in that order. +pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { + return SplitIterator{ + .index = 0, + .buffer = buffer, + .split_bytes = delimiter, + .glob = false, + .spun = false, + }; +} + +test "mem.separate" { + var it = separate("abc|def||ghi", "|"); + assert(eql(u8, it.next().?, "abc")); + assert(eql(u8, it.next().?, "def")); + assert(eql(u8, it.next().?, "")); + assert(eql(u8, it.next().?, "ghi")); + assert(it.next() == null); + + it = separate("", "|"); + assert(eql(u8, it.next().?, "")); + assert(it.next() == null); + + it = separate("|", "|"); + assert(eql(u8, it.next().?, "")); + assert(eql(u8, it.next().?, "")); + assert(it.next() == null); + + it = separate("hello", ""); + assert(eql(u8, it.next().?, "hello")); + assert(it.next() == null); + + it = separate("hello", " "); + assert(eql(u8, it.next().?, "hello")); + assert(it.next() == null); + } pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { @@ -645,20 +719,32 @@ pub const SplitIterator = struct { buffer: []const u8, split_bytes: []const u8, index: usize, + glob: bool, + spun: bool, + /// Iterates and returns null or optionally a slice the next split segment pub fn next(self: *SplitIterator) ?[]const u8 { - // move to beginning of token - while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} - const start = self.index; - if (start == self.buffer.len) { - return null; + if (self.spun) { + if (self.index + 1 > self.buffer.len) return null; + self.index += 1; } - // move to end of token - while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} - const end = self.index; + self.spun = true; - return self.buffer[start..end]; + if (self.glob) { + while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} + } + + var cursor = self.index; + while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {} + + defer self.index = cursor; + + if (cursor == self.buffer.len) { + return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..]; + } + + return self.buffer[self.index..cursor]; } /// Returns a slice of the remaining bytes. Does not affect iterator state. diff --git a/std/os/path.zig b/std/os/path.zig index 0d636353a8..2938c9ab9d 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -967,12 +967,14 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) // shave off the trailing slash result_index -= 1; - var rest_it = mem.split(to_rest, "/\\"); - while (rest_it.next()) |to_component| { - result[result_index] = '\\'; - result_index += 1; - mem.copy(u8, result[result_index..], to_component); - result_index += to_component.len; + if (to_rest.len > 0) { + var rest_it = mem.split(to_rest, "/\\"); + while (rest_it.next()) |to_component| { + result[result_index] = '\\'; + result_index += 1; + mem.copy(u8, result[result_index..], to_component); + result_index += to_component.len; + } } return result[0..result_index]; From 6a1a2898b1e44d7cd799286fb8b6fda06e3803da Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Fri, 30 Nov 2018 00:40:47 +0900 Subject: [PATCH 002/218] std.mem: remove varargs on join to stop excessive inlined code; join was preducing inline code for every unique call causing code bloat --- std/mem.zig | 61 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index 9914a08e65..ae9ea48c29 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -681,7 +681,53 @@ pub const SplitIterator = struct { /// Naively combines a series of strings with a separator. /// Allocates memory for the result, which must be freed by the caller. -pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { +pub fn join(allocator: *Allocator, sep: u8, strings: []const []const u8) ![]u8 { + assert(strings.len >= 1); + var total_strings_len: usize = strings.len; // 1 sep per string + { + var string_i: usize = 0; + while (string_i < strings.len) : (string_i += 1) { + const arg = ([]const u8)(strings[string_i]); + total_strings_len += arg.len; + } + } + + const buf = try allocator.alloc(u8, total_strings_len); + errdefer allocator.free(buf); + + var buf_index: usize = 0; + var string_i: usize = 0; + while (true) { + const arg = ([]const u8)(strings[string_i]); + string_i += 1; + copy(u8, buf[buf_index..], arg); + buf_index += arg.len; + if (string_i >= strings.len) break; + buf[buf_index] = sep; + buf_index += 1; + } + + return allocator.shrink(u8, buf, buf_index); +} + +test "mem.join" { + var str: []u8 = try join(debug.global_allocator, ',', [][]const u8{"a", "b", "c"} ); + errdefer debug.global_allocator.free( str ); + assert(eql(u8, str, "a,b,c")); + debug.global_allocator.free( str ); + + str = try join(debug.global_allocator, ',', [][]const u8{"a"}); + assert(eql(u8, str, "a")); + debug.global_allocator.free( str ); + + str = try join(debug.global_allocator, ',', [][]const u8{"a", ([]const u8)(""), "b", ([]const u8)(""), "c"}); + assert(eql(u8, str, "a,,b,,c")); + debug.global_allocator.free( str ); +} + +/// Naively combines a series of strings with a separator inline. +/// Allocates memory for the result, which must be freed by the caller. +pub fn joinInline(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { comptime assert(strings.len >= 1); var total_strings_len: usize = strings.len; // 1 sep per string { @@ -703,18 +749,17 @@ pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { copy(u8, buf[buf_index..], arg); buf_index += arg.len; if (string_i >= strings.len) break; - if (buf[buf_index - 1] != sep) { - buf[buf_index] = sep; - buf_index += 1; - } + buf[buf_index] = sep; + buf_index += 1; } return allocator.shrink(u8, buf, buf_index); } -test "mem.join" { - assert(eql(u8, try join(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); - assert(eql(u8, try join(debug.global_allocator, ',', "a"), "a")); +test "mem.joinInline" { + assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); + assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", ([]const u8)(""), "c"), "a,b,,c")); + assert(eql(u8, try joinInline(debug.global_allocator, ',', "a"), "a")); } test "testStringEquality" { From ff1b2889f3819610aee17ddbecdf716eb573ca2f Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Fri, 30 Nov 2018 02:17:15 +0900 Subject: [PATCH 003/218] std.mem: split: test for multiple seperator bytes; --- std/mem.zig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/std/mem.zig b/std/mem.zig index adb8b05956..e27ad1a015 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -654,6 +654,16 @@ test "mem.split" { assert(it.next() == null); } +test "mem.split (multibyte)" { + var it = split("a|b,c/d e", " /,|"); + assert(eql(u8, it.next().?, "a")); + assert(eql(u8, it.next().?, "b")); + assert(eql(u8, it.next().?, "c")); + assert(eql(u8, it.next().?, "d")); + assert(eql(u8, it.next().?, "e")); + assert(it.next() == null); +} + /// Returns an iterator that iterates over the slices of `buffer` that /// seperates by bytes in `delimiter`. /// separate("abc|def||ghi", "|") @@ -694,7 +704,16 @@ test "mem.separate" { it = separate("hello", " "); assert(eql(u8, it.next().?, "hello")); assert(it.next() == null); +} +test "mem.separate (multibyte)" { + var it = separate("a|b,c/d e", " /,|"); + assert(eql(u8, it.next().?, "a")); + assert(eql(u8, it.next().?, "b")); + assert(eql(u8, it.next().?, "c")); + assert(eql(u8, it.next().?, "d")); + assert(eql(u8, it.next().?, "e")); + assert(it.next() == null); } pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { From 2b78a90424ee47ee1a9ef590dcf517026d0f13d1 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Fri, 30 Nov 2018 00:37:01 +0900 Subject: [PATCH 004/218] std.os.path: remove dependance on std.mem.join; std/os/child_process.zig: windows test/cli.zig: godbolt; doc/docgen.zig --- build.zig | 16 ++++---- doc/docgen.zig | 10 ++--- std/build.zig | 34 ++++++++-------- std/debug/index.zig | 2 +- std/event/fs.zig | 2 +- std/os/child_process.zig | 2 +- std/os/get_app_data_dir.zig | 6 +-- std/os/path.zig | 79 ++++++++++++++++++++++++------------- test/cli.zig | 6 +-- test/tests.zig | 22 +++++------ 10 files changed, 101 insertions(+), 78 deletions(-) diff --git a/build.zig b/build.zig index e411ae8b21..771600f4ca 100644 --- a/build.zig +++ b/build.zig @@ -16,7 +16,7 @@ pub fn build(b: *Builder) !void { var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); - const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable; + const langref_out_path = os.path.join(b.allocator, [][]const u8{ b.cache_root, "langref.html" }) catch unreachable; var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{ docgen_exe.getOutputPath(), rel_zig_exe, @@ -125,13 +125,13 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { for (dep.libdirs.toSliceConst()) |lib_dir| { lib_exe_obj.addLibPath(lib_dir); } - const lib_dir = os.path.join(b.allocator, dep.prefix, "lib") catch unreachable; + const lib_dir = os.path.join(b.allocator, [][]const u8{dep.prefix, "lib"}) catch unreachable; for (dep.system_libs.toSliceConst()) |lib| { const static_bare_name = if (mem.eql(u8, lib, "curses")) ([]const u8)("libncurses.a") else b.fmt("lib{}.a", lib); - const static_lib_name = os.path.join(b.allocator, lib_dir, static_bare_name) catch unreachable; + const static_lib_name = os.path.join(b.allocator, [][]const u8{lib_dir, static_bare_name}) catch unreachable; const have_static = fileExists(static_lib_name) catch unreachable; if (have_static) { lib_exe_obj.addObjectFile(static_lib_name); @@ -159,7 +159,7 @@ fn fileExists(filename: []const u8) !bool { fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void { const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib"; - lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable); + lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{ cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()) }) catch unreachable); } const LibraryDep = struct { @@ -235,8 +235,8 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { var it = mem.split(stdlib_files, ";"); while (it.next()) |stdlib_file| { - const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable; - const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable; + const src_path = os.path.join(b.allocator, [][]const u8{"std", stdlib_file}) catch unreachable; + const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "std", stdlib_file}) catch unreachable; b.installFile(src_path, dest_path); } } @@ -244,8 +244,8 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { var it = mem.split(c_header_files, ";"); while (it.next()) |c_header_file| { - const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable; - const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable; + const src_path = os.path.join(b.allocator, [][]const u8{"c_headers", c_header_file}) catch unreachable; + const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "include", c_header_file}) catch unreachable; b.installFile(src_path, dest_path); } } diff --git a/doc/docgen.zig b/doc/docgen.zig index 2489e034bc..8b2a7e4c10 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -990,13 +990,13 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var try tokenizeAndPrint(tokenizer, out, code.source_token); try out.write(""); const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name); - const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext); + const tmp_source_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_ext }); try io.writeFile(tmp_source_file_name, trimmed_raw_source); switch (code.id) { Code.Id.Exe => |expected_outcome| { const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext); - const tmp_bin_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_bin_ext); + const tmp_bin_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_bin_ext }); var build_args = std.ArrayList([]const u8).init(allocator); defer build_args.deinit(); try build_args.appendSlice([][]const u8{ @@ -1024,7 +1024,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } for (code.link_objects) |link_object| { const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext); - const full_path_object = try os.path.join(allocator, tmp_dir_name, name_with_ext); + const full_path_object = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_with_ext }); try build_args.append("--object"); try build_args.append(full_path_object); try out.print(" --object {}", name_with_ext); @@ -1216,12 +1216,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var }, Code.Id.Obj => |maybe_error_match| { const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext); - const tmp_obj_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_obj_ext); + const tmp_obj_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_obj_ext }); var build_args = std.ArrayList([]const u8).init(allocator); defer build_args.deinit(); const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name); - const output_h_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_h_ext); + const output_h_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_h_ext }); try build_args.appendSlice([][]const u8{ zig_exe, diff --git a/std/build.zig b/std/build.zig index 5d894eeeb1..0b8c172264 100644 --- a/std/build.zig +++ b/std/build.zig @@ -145,8 +145,8 @@ pub const Builder = struct { pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void { self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default - self.lib_dir = os.path.join(self.allocator, self.prefix, "lib") catch unreachable; - self.exe_dir = os.path.join(self.allocator, self.prefix, "bin") catch unreachable; + self.lib_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "lib"}) catch unreachable; + self.exe_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "bin"}) catch unreachable; } pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { @@ -666,7 +666,7 @@ pub const Builder = struct { if (os.path.isAbsolute(name)) { return name; } - const full_path = try os.path.join(self.allocator, search_prefix, "bin", self.fmt("{}{}", name, exe_extension)); + const full_path = try os.path.join(self.allocator, [][]const u8{search_prefix, "bin", self.fmt("{}{}", name, exe_extension)}); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -681,7 +681,7 @@ pub const Builder = struct { } var it = mem.split(PATH, []u8{os.path.delimiter}); while (it.next()) |path| { - const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); + const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)}); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -695,7 +695,7 @@ pub const Builder = struct { return name; } for (paths) |path| { - const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); + const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)}); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -1095,7 +1095,7 @@ pub const LibExeObjStep = struct { } pub fn getOutputPath(self: *LibExeObjStep) []const u8 { - return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename) catch unreachable; + return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_filename}) catch unreachable; } pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void { @@ -1108,7 +1108,7 @@ pub const LibExeObjStep = struct { } pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { - return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename) catch unreachable; + return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_h_filename}) catch unreachable; } pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { @@ -1208,7 +1208,7 @@ pub const LibExeObjStep = struct { } if (self.build_options_contents.len() > 0) { - const build_options_file = try os.path.join(builder.allocator, builder.cache_root, builder.fmt("{}_build_options.zig", self.name)); + const build_options_file = try os.path.join(builder.allocator, [][]const u8{builder.cache_root, builder.fmt("{}_build_options.zig", self.name)}); try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst()); try zig_args.append("--pkg-begin"); try zig_args.append("build_options"); @@ -1455,7 +1455,7 @@ pub const LibExeObjStep = struct { cc_args.append("-c") catch unreachable; cc_args.append(abs_source_file) catch unreachable; - const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable; + const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable; if (os.path.dirname(cache_o_src)) |cache_o_dir| { try builder.makePath(cache_o_dir); } @@ -1507,7 +1507,7 @@ pub const LibExeObjStep = struct { cc_args.append("-current_version") catch unreachable; cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable; - const install_name = builder.pathFromRoot(os.path.join(builder.allocator, builder.cache_root, self.major_only_filename) catch unreachable); + const install_name = builder.pathFromRoot(os.path.join(builder.allocator, [][]const u8{builder.cache_root, self.major_only_filename}) catch unreachable); cc_args.append("-install_name") catch unreachable; cc_args.append(install_name) catch unreachable; } else { @@ -1573,7 +1573,7 @@ pub const LibExeObjStep = struct { cc_args.append("-c") catch unreachable; cc_args.append(abs_source_file) catch unreachable; - const cache_o_src = os.path.join(builder.allocator, builder.cache_root, source_file) catch unreachable; + const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable; if (os.path.dirname(cache_o_src)) |cache_o_dir| { try builder.makePath(cache_o_dir); } @@ -1721,7 +1721,7 @@ pub const TestStep = struct { return output_path; } else { const basename = self.builder.fmt("test{}", self.target.exeFileExt()); - return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable; + return os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, basename}) catch unreachable; } } @@ -1930,13 +1930,13 @@ const InstallArtifactStep = struct { .builder = builder, .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), .artifact = artifact, - .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, + .dest_file = os.path.join(builder.allocator, [][]const u8{dest_dir, artifact.out_filename}) catch unreachable, }) catch unreachable; self.step.dependOn(&artifact.step); builder.pushInstalledFile(self.dest_file); if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { - builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename) catch unreachable); - builder.pushInstalledFile(os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename) catch unreachable); + builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.major_only_filename}) catch unreachable); + builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.name_only_filename}) catch unreachable); } return self; } @@ -2092,13 +2092,13 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj const out_dir = os.path.dirname(output_path) orelse "."; const out_basename = os.path.basename(output_path); // sym link for libfoo.so.1 to libfoo.so.1.2.3 - const major_only_path = os.path.join(allocator, out_dir, filename_major_only) catch unreachable; + const major_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_major_only}) catch unreachable; os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| { warn("Unable to symlink {} -> {}\n", major_only_path, out_basename); return err; }; // sym link for libfoo.so to libfoo.so.1 - const name_only_path = os.path.join(allocator, out_dir, filename_name_only) catch unreachable; + const name_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_name_only}) catch unreachable; os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| { warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only); return err; diff --git a/std/debug/index.zig b/std/debug/index.zig index c317432654..7596d80d9b 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1290,7 +1290,7 @@ const LineNumberProgram = struct { return error.InvalidDebugInfo; } else self.include_dirs[file_entry.dir_index]; - const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name); + 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, diff --git a/std/event/fs.zig b/std/event/fs.zig index 1b8e1aa5dc..c4d3eaaf9c 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -1339,7 +1339,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { } async fn testFsWatch(loop: *Loop) !void { - const file_path = try os.path.join(loop.allocator, test_tmp_dir, "file.txt"); + const file_path = try os.path.join(loop.allocator, [][]const u8{test_tmp_dir, "file.txt"}); defer loop.allocator.free(file_path); const contents = diff --git a/std/os/child_process.zig b/std/os/child_process.zig index c8865bfacd..9433a7e08f 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -596,7 +596,7 @@ pub const ChildProcess = struct { var it = mem.split(PATH, ";"); while (it.next()) |search_path| { - const joined_path = try os.path.join(self.allocator, search_path, app_name); + const joined_path = try os.path.join(self.allocator, [][]const u8{ search_path, app_name }); defer self.allocator.free(joined_path); const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name); diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig index ae133bb4b1..a0315b4511 100644 --- a/std/os/get_app_data_dir.zig +++ b/std/os/get_app_data_dir.zig @@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD error.OutOfMemory => return error.OutOfMemory, }; defer allocator.free(global_dir); - return os.path.join(allocator, global_dir, appname); + return os.path.join(allocator, [][]const u8{global_dir, appname}); }, os.windows.E_OUTOFMEMORY => return error.OutOfMemory, else => return error.AppDataDirUnavailable, @@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD // TODO look in /etc/passwd return error.AppDataDirUnavailable; }; - return os.path.join(allocator, home_dir, "Library", "Application Support", appname); + return os.path.join(allocator, [][]const u8{home_dir, "Library", "Application Support", appname}); }, builtin.Os.linux, builtin.Os.freebsd => { const home_dir = os.getEnvPosix("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; }; - return os.path.join(allocator, home_dir, ".local", "share", appname); + return os.path.join(allocator, [][]const u8{home_dir, ".local", "share", appname}); }, else => @compileError("Unsupported OS"), } diff --git a/std/os/path.zig b/std/os/path.zig index af767b0dca..acea686915 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -35,38 +35,61 @@ pub fn isSep(byte: u8) bool { /// Naively combines a series of paths with the native path seperator. /// Allocates memory for the result, which must be freed by the caller. -pub fn join(allocator: *Allocator, paths: ...) ![]u8 { - if (is_windows) { - return joinWindows(allocator, paths); - } else { - return joinPosix(allocator, paths); + +pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 { + assert(paths.len >= 1); + var total_paths_len: usize = paths.len; // 1 sep per path + { + var path_i: usize = 0; + while (path_i < paths.len) : (path_i += 1) { + const arg = ([]const u8)(paths[path_i]); + total_paths_len += arg.len; + } } -} -pub fn joinWindows(allocator: *Allocator, paths: ...) ![]u8 { - return mem.join(allocator, sep_windows, paths); -} + const buf = try allocator.alloc(u8, total_paths_len); + errdefer allocator.free(buf); -pub fn joinPosix(allocator: *Allocator, paths: ...) ![]u8 { - return mem.join(allocator, sep_posix, paths); + var buf_index: usize = 0; + var path_i: usize = 0; + while (true) { + const arg = ([]const u8)(paths[path_i]); + path_i += 1; + mem.copy(u8, buf[buf_index..], arg); + buf_index += arg.len; + if (path_i >= paths.len) break; + if (buf_index > 0 and buf[buf_index - 1] != sep) { + buf[buf_index] = sep; + buf_index += 1; + } + } + + return allocator.shrink(u8, buf, buf_index); } test "os.path.join" { - assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b", "c"), "c:\\a\\b\\c")); - assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\b\\", "c"), "c:\\a\\b\\c")); - - assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\", "a", "b\\", "c"), "c:\\a\\b\\c")); - assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\a\\", "b\\", "c"), "c:\\a\\b\\c")); - - assert(mem.eql(u8, try joinWindows(debug.global_allocator, "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig"), "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig")); - - assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b", "c"), "/a/b/c")); - assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/b/", "c"), "/a/b/c")); - - assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c")); - assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/a/", "b/", "c"), "/a/b/c")); - - assert(mem.eql(u8, try joinPosix(debug.global_allocator, "/home/andy/dev/zig/build/lib/zig/std", "io.zig"), "/home/andy/dev/zig/build/lib/zig/std/io.zig")); + switch (builtin.os) { + Os.windows => { + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b", "c"}), "c:\\a\\b\\c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b\\", "c"}), "c:\\a\\b\\c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\", "a", "b\\", "c"}), "c:\\a\\b\\c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\", "b\\", "c"}), "c:\\a\\b\\c")); + assert(mem.eql(u8, try join( debug.global_allocator + , [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std" + , "io.zig"}) + , "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig")); + }, + else => { + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b", "c"}), "/a/b/c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b/", "c"}), "/a/b/c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/", "a", "b/", "c"}), "/a/b/c")); + assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/", "b/", "c"}), "/a/b/c")); + assert(mem.eql(u8, try join( debug.global_allocator + , [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std" + , "io.zig"}) + , "/home/andy/dev/zig/build/lib/zig/std/io.zig")); + } + } } pub fn isAbsolute(path: []const u8) bool { @@ -598,7 +621,7 @@ test "os.path.resolveWindows" { const parsed_cwd = windowsParsePath(cwd); { const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }); - const expected = try join(debug.global_allocator, parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"); + const expected = try join(debug.global_allocator, [][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"}); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } @@ -606,7 +629,7 @@ test "os.path.resolveWindows" { } { const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" }); - const expected = try join(debug.global_allocator, cwd, "usr\\local\\lib\\zig"); + const expected = try join(debug.global_allocator, [][]const u8{ cwd, "usr\\local\\lib\\zig" }); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } diff --git a/test/cli.zig b/test/cli.zig index a07c447d2d..0980e8c2d8 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -29,7 +29,7 @@ pub fn main() !void { }); const zig_exe = try os.path.resolve(a, zig_exe_rel); - const dir_path = try os.path.join(a, cache_root, "clitest"); + const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" }); const TestFn = fn ([]const u8, []const u8) anyerror!void; const test_fns = []TestFn{ testZigInitLib, @@ -99,8 +99,8 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { if (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64) return; - const example_zig_path = try os.path.join(a, dir_path, "example.zig"); - const example_s_path = try os.path.join(a, dir_path, "example.s"); + const example_zig_path = try os.path.join(a, [][]const u8{ dir_path, "example.zig" }); + const example_s_path = try os.path.join(a, [][]const u8{ dir_path, "example.s" }); try std.io.writeFile(example_zig_path, \\// Type your code here, or load an example. diff --git a/test/tests.zig b/test/tests.zig index 1ca06b4b34..ef4fb996e2 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -420,7 +420,7 @@ pub const CompareOutputContext = struct { pub fn addCase(self: *CompareOutputContext, case: TestCase) void { const b = self.b; - const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable; + const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable; switch (case.special) { Special.Asm => { @@ -433,7 +433,7 @@ pub const CompareOutputContext = struct { exe.addAssemblyFile(root_src); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -457,7 +457,7 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -480,7 +480,7 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -552,8 +552,8 @@ pub const CompileErrorContext = struct { const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); const b = self.context.b; - const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable; - const obj_path = os.path.join(b.allocator, b.cache_root, "test.o") catch unreachable; + const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable; + const obj_path = os.path.join(b.allocator, [][]const u8{b.cache_root, "test.o"}) catch unreachable; var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; @@ -700,7 +700,7 @@ pub const CompileErrorContext = struct { self.step.dependOn(&compile_and_cmp_errors.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); compile_and_cmp_errors.step.dependOn(&write_src.step); } @@ -830,7 +830,7 @@ pub const TranslateCContext = struct { const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); const b = self.context.b; - const root_src = os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename) catch unreachable; + const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable; var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; @@ -963,7 +963,7 @@ pub const TranslateCContext = struct { self.step.dependOn(&translate_c_and_cmp.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); translate_c_and_cmp.step.dependOn(&write_src.step); } @@ -1076,7 +1076,7 @@ pub const GenHContext = struct { pub fn addCase(self: *GenHContext, case: *const TestCase) void { const b = self.b; - const root_src = os.path.join(b.allocator, b.cache_root, case.sources.items[0].filename) catch unreachable; + const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable; const mode = builtin.Mode.Debug; const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable; @@ -1088,7 +1088,7 @@ pub const GenHContext = struct { obj.setBuildMode(mode); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, b.cache_root, src_file.filename) catch unreachable; + const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); obj.step.dependOn(&write_src.step); } From 1e60ca4b752a61e26067b4893be623442836ec6f Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Fri, 30 Nov 2018 01:51:31 +0900 Subject: [PATCH 005/218] stage2: update std.os.path.join method signature; stage2: take 2; --- src-self-hosted/compilation.zig | 6 +++--- src-self-hosted/introspect.zig | 4 ++-- src-self-hosted/libc_installation.zig | 8 ++++---- src-self-hosted/link.zig | 2 +- src-self-hosted/main.zig | 2 +- src-self-hosted/test.zig | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index a8c3e13e33..c3eae1f803 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -485,7 +485,7 @@ pub const Compilation = struct { comp.name = try Buffer.init(comp.arena(), name); comp.llvm_triple = try target.getTriple(comp.arena()); comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple); - comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std"); + comp.zig_std_dir = try std.os.path.join(comp.arena(), [][]const u8{ zig_lib_dir, "std" }); const opt_level = switch (build_mode) { builtin.Mode.Debug => llvm.CodeGenLevelNone, @@ -1183,7 +1183,7 @@ pub const Compilation = struct { const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix); defer self.gpa().free(file_name); - const full_path = try os.path.join(self.gpa(), tmp_dir, file_name[0..]); + const full_path = try os.path.join(self.gpa(), [][]const u8{ tmp_dir, file_name[0..] }); errdefer self.gpa().free(full_path); return Buffer.fromOwnedSlice(self.gpa(), full_path); @@ -1204,7 +1204,7 @@ pub const Compilation = struct { const zig_dir_path = try getZigDir(self.gpa()); defer self.gpa().free(zig_dir_path); - const tmp_dir = try os.path.join(self.arena(), zig_dir_path, comp_dir_name[0..]); + const tmp_dir = try os.path.join(self.arena(), [][]const u8{ zig_dir_path, comp_dir_name[0..] }); try os.makePath(self.gpa(), tmp_dir); return tmp_dir; } diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig index d41f82f755..0a7f63b4f1 100644 --- a/src-self-hosted/introspect.zig +++ b/src-self-hosted/introspect.zig @@ -8,10 +8,10 @@ const warn = std.debug.warn; /// Caller must free result pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { - const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); + 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, test_zig_dir, "std", "index.zig"); + const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "index.zig" }); defer allocator.free(test_index_file); var file = try os.File.openRead(test_index_file); diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index 1c5d111c5a..6e8c997c08 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -230,7 +230,7 @@ pub const LibCInstallation = struct { while (path_i < search_paths.len) : (path_i += 1) { const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); - const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h"); + const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ search_path, "stdlib.h" }); defer loop.allocator.free(stdlib_path); if (try fileExists(stdlib_path)) { @@ -254,7 +254,7 @@ pub const LibCInstallation = struct { const stream = &std.io.BufferOutStream.init(&result_buf).stream; try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version); - const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h"); + const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "stdlib.h" }); defer loop.allocator.free(stdlib_path); if (try fileExists(stdlib_path)) { @@ -283,7 +283,7 @@ pub const LibCInstallation = struct { builtin.Arch.aarch64v8 => try stream.write("arm"), else => return error.UnsupportedArchitecture, } - const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib"); + const ucrt_lib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" }); defer loop.allocator.free(ucrt_lib_path); if (try fileExists(ucrt_lib_path)) { self.lib_dir = result_buf.toOwnedSlice(); @@ -358,7 +358,7 @@ pub const LibCInstallation = struct { builtin.Arch.aarch64v8 => try stream.write("arm\\"), else => return error.UnsupportedArchitecture, } - const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib"); + const kernel32_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" }); defer loop.allocator.free(kernel32_path); if (try fileExists(kernel32_path)) { self.kernel32_lib_dir = result_buf.toOwnedSlice(); diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 1b32533ebc..fadc9b0189 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -315,7 +315,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { } fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { - const full_path = try std.os.path.join(&ctx.arena.allocator, dirname, basename); + const full_path = try std.os.path.join(&ctx.arena.allocator, [][]const u8{ dirname, basename }); const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path); try ctx.args.append(full_path_with_null.ptr); } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 0742cbfe65..36aab4141b 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -757,7 +757,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro var group = event.Group(FmtError!void).init(fmt.loop); while (try dir.next()) |entry| { if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) { - const full_path = try os.path.join(fmt.loop.allocator, file_path, entry.name); + const full_path = try os.path.join(fmt.loop.allocator, [][]const u8{ file_path, entry.name }); try group.call(fmtPath, fmt, full_path, check_mode); } } diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index ff5b96df84..de551cf7f7 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -87,7 +87,7 @@ pub const TestContext = struct { ) !void { var file_index_buf: [20]u8 = undefined; const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr()); - const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1); + const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 }); if (std.os.path.dirname(file1_path)) |dirname| { try std.os.makePath(allocator, dirname); @@ -120,7 +120,7 @@ pub const TestContext = struct { ) !void { var file_index_buf: [20]u8 = undefined; const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr()); - const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1); + const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 }); const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt()); if (std.os.path.dirname(file1_path)) |dirname| { From 5dfca87a65884f8564a8c8e2444bb906073425f3 Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 22 Nov 2018 04:15:22 -0600 Subject: [PATCH 006/218] Update windows imports --- std/os/index.zig | 81 ++++++++++++++++++++++++++++++++----- std/os/windows/kernel32.zig | 6 +-- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 15be08c689..85e7eab01c 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -702,8 +702,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { errdefer result.deinit(); if (is_windows) { - const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory; - defer assert(windows.FreeEnvironmentStringsA(ptr) != 0); + const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; + defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); var i: usize = 0; while (true) { @@ -712,17 +712,50 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const key_start = i; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - const key = ptr[key_start..i]; + + const stack_var_len = 50; + const key_slice = ptr[key_start..i]; + var key: []u8 = undefined; + var heap_key = false; + + // parse the key on the stack if smaller than 'stack_var_len' + if (key_slice.len < stack_var_len-@sizeOf(usize)) { + var buf = []u8{0} ** stack_var_len; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); + } else { + key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); + heap_key = true; // key needs to outlive this scope, so we cannot defer + } if (ptr[i] == '=') i += 1; const value_start = i; while (ptr[i] != 0) : (i += 1) {} - const value = ptr[value_start..i]; + + const value_slice = ptr[value_start..i]; + var value: []u8 = undefined; + var heap_value = false; + + if (value_slice.len < stack_var_len-@sizeOf(usize)) { + var buf = []u8{0} ** stack_var_len; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); + } else { + value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); + heap_value = true; // value needs to outlive this scope, so we cannot defer + } i += 1; // skip over null byte try result.set(key, value); + + if (heap_key) { + allocator.free(key); + } + if (heap_value) { + allocator.free(value); + } } } else { for (posix_environ_raw) |ptr| { @@ -740,6 +773,19 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } } +test "os.getEnvMap" { + var env = try getEnvMap(std.debug.global_allocator); + var seen_path = false; + var it = env.iterator(); + while (it.next()) |pair| { + if (mem.eql(u8, pair.key, "PATH")) { + seen_path = true; + } + } + + assert(seen_path == true); +} + /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { for (posix_environ_raw) |ptr| { @@ -760,21 +806,27 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { pub const GetEnvVarOwnedError = error{ OutOfMemory, EnvironmentVariableNotFound, + DanglingSurrogateHalf, + ExpectedSecondSurrogateHalf, + UnexpectedSecondSurrogateHalf, + + /// 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 cstr.addNullByte(allocator, key); + const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); defer allocator.free(key_with_null); - var buf = try allocator.alloc(u8, 256); - errdefer allocator.free(buf); + 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.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len); + const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len); if (result == 0) { const err = windows.GetLastError(); @@ -788,11 +840,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } if (result > buf.len) { - buf = try allocator.realloc(u8, buf, result); + buf = try allocator.realloc(u16, buf, result); continue; } - return allocator.shrink(u8, buf, result); + return try std.unicode.utf16leToUtf8Alloc(allocator, buf); } } else { const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; @@ -800,6 +852,15 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } } +test "os.getEnvVarOwned" { + switch (builtin.os) { + builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"), + else => @compileError("unimplemented"), + } +} + + /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 7eec5faba9..202b8bffeb 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL; pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL; -pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL; +pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL; pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR; @@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE; pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD; -pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8; +pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16; -pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD; +pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD; pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL; From 0abd5520bdc8118369895f67f581d10c847ac139 Mon Sep 17 00:00:00 2001 From: Suirad Date: Sat, 24 Nov 2018 17:29:06 -0600 Subject: [PATCH 007/218] Platform specific tests --- std/os/index.zig | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 85e7eab01c..62059a335b 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -775,15 +775,26 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { test "os.getEnvMap" { var env = try getEnvMap(std.debug.global_allocator); - var seen_path = false; + var seen_home = false; var it = env.iterator(); while (it.next()) |pair| { - if (mem.eql(u8, pair.key, "PATH")) { - seen_path = true; - } + switch (builtin.os){ + builtin.Os.windows => { + if (mem.eql(u8, pair.key, "HOMEPATH")) { + seen_home = true; + } + }, + builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => { + if (mem.eql(u8, pair.key, "HOME")) { + seen_home = true; + } + }, + else => @compileError("unimplemented"), + } } - assert(seen_path == true); + assert(seen_home == true); } /// TODO make this go through libc when we have it @@ -854,8 +865,10 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned test "os.getEnvVarOwned" { switch (builtin.os) { - builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"), + builtin.Os.windows => _ = try getEnvVarOwned(debug.global_allocator, "HOMEPATH"), + + builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "HOME"), else => @compileError("unimplemented"), } } From 24592d0216ce4830e9f0dd51a7d2542f1f8afa05 Mon Sep 17 00:00:00 2001 From: Suirad Date: Sat, 24 Nov 2018 19:21:12 -0600 Subject: [PATCH 008/218] Add more padding to parse buffer --- std/os/index.zig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 62059a335b..4272374b3a 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -15,7 +15,7 @@ test "std.os" { _ = @import("get_user_id.zig"); _ = @import("linux/index.zig"); _ = @import("path.zig"); - _ = @import("test.zig"); + _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); _ = @import("get_app_data_dir.zig"); @@ -718,8 +718,9 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var key: []u8 = undefined; var heap_key = false; - // parse the key on the stack if smaller than 'stack_var_len' - if (key_slice.len < stack_var_len-@sizeOf(usize)) { + /// revisit needing the "-@sizeof(usize)*2" + /// after https://github.com/ziglang/zig/issues/1774 + if (key_slice.len < stack_var_len-@sizeOf(usize)*2) { var buf = []u8{0} ** stack_var_len; var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); @@ -737,7 +738,9 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var value: []u8 = undefined; var heap_value = false; - if (value_slice.len < stack_var_len-@sizeOf(usize)) { + /// revisit needing the "-@sizeof(usize)*2" + /// after https://github.com/ziglang/zig/issues/1774 + if (value_slice.len < stack_var_len-@sizeOf(usize)*2) { var buf = []u8{0} ** stack_var_len; var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); From 1fa2217c1008fefa7084ea34fedcf79ad214a02e Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 29 Nov 2018 03:24:36 -0600 Subject: [PATCH 009/218] Simplify implementation --- std/os/index.zig | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 4272374b3a..cc7479b871 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -15,7 +15,7 @@ test "std.os" { _ = @import("get_user_id.zig"); _ = @import("linux/index.zig"); _ = @import("path.zig"); - _ = @import("test.zig"); + _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); _ = @import("get_app_data_dir.zig"); @@ -705,28 +705,26 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); + var buf: [100]u8 = undefined; + var i: usize = 0; while (true) { if (ptr[i] == 0) return result; const key_start = i; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - const stack_var_len = 50; const key_slice = ptr[key_start..i]; var key: []u8 = undefined; var heap_key = false; - /// revisit needing the "-@sizeof(usize)*2" - /// after https://github.com/ziglang/zig/issues/1774 - if (key_slice.len < stack_var_len-@sizeOf(usize)*2) { - var buf = []u8{0} ** stack_var_len; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); - } else { + key = std.unicode.utf16leToUtf8Alloc(fallocator, key_slice) catch undefined; + + if (key.len == 0) { key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); - heap_key = true; // key needs to outlive this scope, so we cannot defer + heap_key = true; } if (ptr[i] == '=') i += 1; @@ -738,15 +736,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var value: []u8 = undefined; var heap_value = false; - /// revisit needing the "-@sizeof(usize)*2" - /// after https://github.com/ziglang/zig/issues/1774 - if (value_slice.len < stack_var_len-@sizeOf(usize)*2) { - var buf = []u8{0} ** stack_var_len; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); - } else { + value = std.unicode.utf16leToUtf8Alloc(fallocator, value_slice) catch undefined; + + if (value.len == 0) { value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); - heap_value = true; // value needs to outlive this scope, so we cannot defer + heap_value = true; } i += 1; // skip over null byte From e8e6ae57d41fdcdb4027ae95c04ad7aeea4a7aac Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 29 Nov 2018 16:03:12 -0600 Subject: [PATCH 010/218] Find CI env variables --- std/os/index.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/std/os/index.zig b/std/os/index.zig index cc7479b871..d298ff4329 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -775,6 +775,7 @@ test "os.getEnvMap" { var seen_home = false; var it = env.iterator(); while (it.next()) |pair| { + debug.warn("{}: {}\n", pair.key, pair.value); switch (builtin.os){ builtin.Os.windows => { if (mem.eql(u8, pair.key, "HOMEPATH")) { From cf266ff80a69d19140465b949350421dc541d4c8 Mon Sep 17 00:00:00 2001 From: Suirad Date: Fri, 30 Nov 2018 02:15:33 -0600 Subject: [PATCH 011/218] Update tests --- std/os/index.zig | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index d298ff4329..779fa8f8c8 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -772,27 +772,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { test "os.getEnvMap" { var env = try getEnvMap(std.debug.global_allocator); - var seen_home = false; - var it = env.iterator(); - while (it.next()) |pair| { - debug.warn("{}: {}\n", pair.key, pair.value); - switch (builtin.os){ - builtin.Os.windows => { - if (mem.eql(u8, pair.key, "HOMEPATH")) { - seen_home = true; - } - }, - builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => { - if (mem.eql(u8, pair.key, "HOME")) { - seen_home = true; - } - }, - else => @compileError("unimplemented"), - } - } - - assert(seen_home == true); + defer env.deinit(); } /// TODO make this go through libc when we have it @@ -862,13 +842,8 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } test "os.getEnvVarOwned" { - switch (builtin.os) { - builtin.Os.windows => _ = try getEnvVarOwned(debug.global_allocator, "HOMEPATH"), - - builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "HOME"), - else => @compileError("unimplemented"), - } + var ga = debug.global_allocator; + debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); } From 1ab66f3b55bbeac3c6f4f02c86a688cdc1bb2476 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Fri, 23 Nov 2018 10:02:14 -0600 Subject: [PATCH 012/218] Added serialization, bitstreams, traits for integer sign, TagPayloadType --- std/io.zig | 639 ++++++++++++++++++++++++++++++++++++++++++++- std/io_test.zig | 329 +++++++++++++++++++++++ std/meta/index.zig | 38 ++- std/meta/trait.zig | 31 +++ 4 files changed, 1029 insertions(+), 8 deletions(-) diff --git a/std/io.zig b/std/io.zig index f4122a2f8b..219db124a0 100644 --- a/std/io.zig +++ b/std/io.zig @@ -8,6 +8,8 @@ const debug = std.debug; const assert = debug.assert; const os = std.os; const mem = std.mem; +const meta = std.meta; +const trait = meta.trait; const Buffer = std.Buffer; const fmt = std.fmt; const File = std.os.File; @@ -444,6 +446,151 @@ pub const SliceInStream = struct { } }; +/// Creates a stream which allows for reading bit fields from another stream +pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { + return struct { + const Self = @This(); + + in_stream: *Stream, + bit_buffer: u7, + bit_count: u3, + stream: Stream, + + pub const Stream = InStream(Error); + const u8_bit_count = comptime meta.bitCount(u8); + const u7_bit_count = comptime meta.bitCount(u7); + const u4_bit_count = comptime meta.bitCount(u4); + + pub fn init(in_stream: *Stream) Self { + return Self{ + .in_stream = in_stream, + .bit_buffer = 0, + .bit_count = 0, + .stream = Stream{ .readFn = read }, + }; + } + + /// Reads `bits` bits from the stream and returns a specified unsigned int type + /// containing them in the least significant end, returning an error if the + /// specified number of bits could not be read. + pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U { + var n: usize = undefined; + const result = try self.readBits(U, bits, &n); + if (n < bits) return error.EndOfStream; + return result; + } + + /// Reads `bits` bits from the stream and returns a specified unsigned int type + /// containing them in the least significant end. The number of bits successfully + /// read is placed in `out_bits`, as reaching the end of the stream is not an error. + pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U { + debug.assert(trait.isUnsignedInt(U)); + + //by extending the buffer to a minimum of u8 we can cover a number of edge cases + // related to shifting and casting. + const u_bit_count = comptime meta.bitCount(U); + const buf_bit_count = bc: { + debug.assert(u_bit_count >= bits); + break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; + }; + const Buf = @IntType(false, buf_bit_count); + const BufShift = math.Log2Int(Buf); + + out_bits.* = usize(0); + if (U == u0 or bits == 0) return 0; + var out_buffer = Buf(0); + + if (self.bit_count > 0) { + const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count; + const shift = u7_bit_count - n; + switch (endian) { + builtin.Endian.Big => { + out_buffer = Buf(self.bit_buffer >> shift); + self.bit_buffer <<= n; + }, + builtin.Endian.Little => { + const value = (self.bit_buffer << shift) >> shift; + out_buffer = Buf(value); + self.bit_buffer >>= n; + }, + } + self.bit_count -= n; + out_bits.* = n; + } + //at this point we know bit_buffer is empty + + //copy bytes until we have enough bits, then leave the rest in bit_buffer + while (out_bits.* < bits) { + const n = bits - out_bits.*; + const next_byte = self.in_stream.readByte() catch |err| { + if (err == error.EndOfStream) { + return @intCast(U, out_buffer); + } + return err; + }; + + switch (endian) { + builtin.Endian.Big => { + if (n >= u8_bit_count) { + out_buffer <<= @intCast(u3, u8_bit_count - 1); + out_buffer <<= 1; + out_buffer |= Buf(next_byte); + out_bits.* += u8_bit_count; + continue; + } + + const shift = @intCast(u3, u8_bit_count - n); + out_buffer <<= @intCast(BufShift, n); + out_buffer |= Buf(next_byte >> shift); + out_bits.* += n; + self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1)); + self.bit_count = shift; + }, + builtin.Endian.Little => { + if (n >= u8_bit_count) { + out_buffer |= Buf(next_byte) << @intCast(BufShift, out_bits.*); + out_bits.* += u8_bit_count; + continue; + } + + const shift = @intCast(u3, u8_bit_count - n); + const value = (next_byte << shift) >> shift; + out_buffer |= Buf(value) << @intCast(BufShift, out_bits.*); + out_bits.* += n; + self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n)); + self.bit_count = shift; + }, + } + } + + return @intCast(U, out_buffer); + } + + pub fn alignToByte(self: *Self) void { + self.bit_buffer = 0; + self.bit_count = 0; + } + + pub fn read(self_stream: *Stream, buffer: []u8) Error!usize { + var self = @fieldParentPtr(Self, "stream", self_stream); + + var out_bits: usize = undefined; + var out_bits_total = usize(0); + //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced + if (self.bit_count > 0) { + for (buffer) |*b, i| { + b.* = try self.readBits(u8, u8_bit_count, &out_bits); + out_bits_total += out_bits; + } + const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0); + return (out_bits_total / u8_bit_count) + incomplete_byte; + } + + return self.in_stream.read(buffer); + } + }; +} + /// This is a simple OutStream that writes to a slice, and returns an error /// when it runs out of space. pub const SliceOutStream = struct { @@ -637,6 +784,137 @@ pub const BufferOutStream = struct { } }; +/// Creates a stream which allows for writing bit fields to another stream +pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { + return struct { + const Self = @This(); + + out_stream: *Stream, + bit_buffer: u8, + bit_count: u4, + stream: Stream, + + pub const Stream = OutStream(Error); + const u8_bit_count = comptime meta.bitCount(u8); + const u4_bit_count = comptime meta.bitCount(u4); + + pub fn init(out_stream: *Stream) Self { + return Self{ + .out_stream = out_stream, + .bit_buffer = 0, + .bit_count = 0, + .stream = Stream{ .writeFn = write }, + }; + } + + /// Write the specified number of bits to the stream from the least significant bits of + /// the specified unsigned int value. Bits will only be written to the stream when there + /// are enough to fill a byte. + pub fn writeBits(self: *Self, value: var, bits: usize) Error!void { + if (bits == 0) return; + + const U = @typeOf(value); + debug.assert(trait.isUnsignedInt(U)); + + //by extending the buffer to a minimum of u8 we can cover a number of edge cases + // related to shifting and casting. + const u_bit_count = comptime meta.bitCount(U); + const buf_bit_count = bc: { + debug.assert(u_bit_count >= bits); + break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; + }; + const Buf = @IntType(false, buf_bit_count); + const BufShift = math.Log2Int(Buf); + + const buf_value = @intCast(Buf, value); + + const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count); + var in_buffer = switch (endian) { + builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits), + builtin.Endian.Little => buf_value, + }; + var in_bits = bits; + + if (self.bit_count > 0) { + const bits_remaining = u8_bit_count - self.bit_count; + const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining); + switch (endian) { + builtin.Endian.Big => { + const shift = @intCast(BufShift, high_byte_shift + self.bit_count); + const v = @intCast(u8, in_buffer >> shift); + self.bit_buffer |= v; + in_buffer <<= n; + }, + builtin.Endian.Little => { + const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count); + self.bit_buffer |= v; + in_buffer >>= n; + }, + } + self.bit_count += n; + in_bits -= n; + + //if we didn't fill the buffer, it's because bits < bits_remaining; + if (self.bit_count != u8_bit_count) return; + try self.out_stream.writeByte(self.bit_buffer); + self.bit_buffer = 0; + self.bit_count = 0; + } + //at this point we know bit_buffer is empty + + //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer + while (in_bits >= u8_bit_count) { + switch (endian) { + builtin.Endian.Big => { + const v = @intCast(u8, in_buffer >> high_byte_shift); + try self.out_stream.writeByte(v); + in_buffer <<= @intCast(u3, u8_bit_count - 1); + in_buffer <<= 1; + }, + builtin.Endian.Little => { + const v = @truncate(u8, in_buffer); + try self.out_stream.writeByte(v); + in_buffer >>= @intCast(u3, u8_bit_count - 1); + in_buffer >>= 1; + }, + } + in_bits -= u8_bit_count; + } + + if (in_bits > 0) { + self.bit_count = @intCast(u4, in_bits); + self.bit_buffer = switch (endian) { + builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift), + builtin.Endian.Little => @truncate(u8, in_buffer), + }; + } + } + + /// Flush any remaining bits to the stream. + pub fn flushBits(self: *Self) !void { + if (self.bit_count == 0) return; + try self.out_stream.writeByte(self.bit_buffer); + self.bit_buffer = 0; + self.bit_count = 0; + } + + pub fn write(self_stream: *Stream, buffer: []const u8) Error!void { + var self = @fieldParentPtr(Self, "stream", self_stream); + + //@NOTE: I'm not sure this is a good idea, maybe flushBits should be forced + if (self.bit_count > 0) { + for (buffer) |b, i| + try self.writeBits(b, u8_bit_count); + return; + } + + return self.out_stream.write(buffer); + } + }; +} + + + pub const BufferedAtomicFile = struct { atomic_file: os.AtomicFile, file_stream: os.File.OutStream, @@ -677,11 +955,6 @@ pub const BufferedAtomicFile = struct { } }; -test "import io tests" { - comptime { - _ = @import("io_test.zig"); - } -} pub fn readLine(buf: *std.Buffer) ![]u8 { var stdin = try getStdIn(); @@ -753,3 +1026,359 @@ test "io.readLineSliceFrom" { debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); } + +/// Creates a deserializer that deserializes types from any stream. +/// If `is_packed` is true, the data stream is treated as bit-packed, +/// otherwise data is expected to be packed to the smallest byte. +/// Types may implement a custom deserialization routine with a +/// function named `deserialize` in the form of: +/// pub fn deserialize(self: *Self, deserializer: var) !void +/// which will be called when the deserializer is used to deserialize +/// that type. It will pass a pointer to the type instance to deserialize +/// into and a pointer to the deserializer struct. +pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { + return struct { + const Self = @This(); + + in_stream: if (is_packed) BitInStream(endian, Stream.Error) else *Stream, + + pub const Stream = InStream(Error); + + pub fn init(in_stream: *Stream) Self { + return Self{ .in_stream = switch (is_packed) { + true => BitInStream(endian, Stream.Error).init(in_stream), + else => in_stream, + } }; + } + + //@BUG: inferred error issue + fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { + debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + + const u8_bit_count = comptime meta.bitCount(u8); + const t_bit_count = comptime meta.bitCount(T); + + const U = @IntType(false, t_bit_count); + const Log2U = math.Log2Int(U); + const int_size = @sizeOf(U); + + if (is_packed) { + const result = try self.in_stream.readBitsNoEof(U, t_bit_count); + return @bitCast(T, result); + } + + var buffer: [int_size]u8 = undefined; + const read_size = try self.in_stream.read(buffer[0..]); + if (read_size < int_size) return error.EndOfStream; + + if (int_size == 1) return @bitCast(T, buffer[0]); + + var result = U(0); + for (buffer) |byte, i| { + switch (endian) { + builtin.Endian.Big => { + result = (result << @intCast(u4, u8_bit_count)) | byte; + }, + builtin.Endian.Little => { + result |= U(byte) << @intCast(Log2U, u8_bit_count * i); + }, + } + } + + return @bitCast(T, result); + } + + //@TODO: Replace this with @unionInit or whatever when it is added + // see: #1315 + fn setTag(ptr: var, tag: var) void { + const T = @typeOf(ptr); + comptime debug.assert(trait.isPtrTo(builtin.TypeId.Union)(T)); + const U = meta.Child(T); + + const info = @typeInfo(U).Union; + if (info.tag_type) |TagType| { + debug.assert(TagType == @typeOf(tag)); + + var ptr_tag = ptr: { + if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr); + const offset = comptime max: { + var max_field_size: comptime_int = 0; + for (info.fields) |field_info| { + const field_size = @sizeOf(field_info.field_type); + max_field_size = math.max(max_field_size, field_size); + } + break :max math.max(max_field_size, @alignOf(U)); + }; + break :ptr @intToPtr(*TagType, @ptrToInt(ptr) + offset); + }; + ptr_tag.* = tag; + } + } + + /// Deserializes and returns data of the specified type from the stream + pub fn deserialize(self: *Self, comptime T: type) !T { + var value: T = undefined; + try self.deserializeInto(&value); + return value; + } + + /// Deserializes data into the type pointed to by `ptr` + pub fn deserializeInto(self: *Self, ptr: var) !void { + const T = @typeOf(ptr); + debug.assert(trait.is(builtin.TypeId.Pointer)(T)); + + if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) { + for (ptr) |*v| + try self.deserializeInto(v); + return; + } + + comptime debug.assert(trait.isSingleItemPtr(T)); + + const C = comptime meta.Child(T); + const child_type_id = @typeId(C); + + //custom deserializer: fn(self: *Self, deserializer: var) !void + if (comptime trait.hasFn("deserialize")(C)) return ptr.deserialize(self); + + if (comptime trait.isPacked(C) and !is_packed) { + var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream); + return packed_deserializer.deserializeInto(ptr); + } + + switch (child_type_id) { + builtin.TypeId.Void => return, + builtin.TypeId.Bool => ptr.* = (try self.deserializeInt(u1)) > 0, + builtin.TypeId.Float, builtin.TypeId.Int => ptr.* = try self.deserializeInt(C), + builtin.TypeId.Struct => { + const info = @typeInfo(C).Struct; + + inline for (info.fields) |*field_info| { + const name = field_info.name; + const FieldType = field_info.field_type; + + if (FieldType == void or FieldType == u0) continue; + + //it doesn't make any sense to read pointers + if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { + @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++ + @typeName(C) ++ " because it " ++ "is of pointer-type " ++ + @typeName(FieldType) ++ "."); + } + + try self.deserializeInto(&@field(ptr, name)); + } + }, + builtin.TypeId.Union => { + const info = @typeInfo(C).Union; + if (info.tag_type) |TagType| { + //we avoid duplicate iteration over the enum tags + // by getting the int directly and casting it without + // safety. If it is bad, it will be caught anyway. + const TagInt = @TagType(TagType); + const tag = try self.deserializeInt(TagInt); + + { + @setRuntimeSafety(false); + //See: #1315 + setTag(ptr, @intToEnum(TagType, tag)); + } + + inline for (info.fields) |field_info| { + if (field_info.enum_field.?.value == tag) { + const name = field_info.name; + const FieldType = field_info.field_type; + @field(ptr, name) = FieldType(undefined); + try self.deserializeInto(&@field(ptr, name)); + return; + } + } + //This is reachable if the enum data is bad + return error.InvalidEnumTag; + } + @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++ + " because it is an untagged union Use a custom deserialize()."); + }, + builtin.TypeId.Optional => { + const OC = comptime meta.Child(C); + const exists = (try self.deserializeInt(u1)) > 0; + if (!exists) { + ptr.* = null; + return; + } + + //The way non-pointer optionals are implemented ensures a pointer to them + // will point to the value. The flag is stored at the end of that data. + var val_ptr = @ptrCast(*OC, ptr); + try self.deserializeInto(val_ptr); + //This bit ensures the null flag isn't set. Any actual copying should be + // optimized out... I hope. + ptr.* = val_ptr.*; + }, + builtin.TypeId.Enum => { + var value = try self.deserializeInt(@TagType(C)); + ptr.* = try meta.intToEnum(C, value); + }, + else => { + @compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented)."); + }, + } + } + }; +} + +/// Creates a serializer that serializes types to any stream. +/// If `is_packed` is true, the data will be bit-packed into the stream. +/// Note that the you must call `serializer.flush()` when you are done +/// writing bit-packed data in order ensure any unwritten bits are committed. +/// If `is_packed` is false, data is packed to the smallest byte. In the case +/// of packed structs, the struct will written bit-packed and with the specified +/// endianess, after which data will resume being written at the next byte boundary. +/// Types may implement a custom serialization routine with a +/// function named `serialize` in the form of: +/// pub fn serialize(self: *const Self, serializer: var) !void +/// which will be called when the serializer is used to serialize that type. It will +/// pass a const pointer to the type instance to be serialized and a pointer +/// to the serializer struct. +pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { + return struct { + const Self = @This(); + + out_stream: if (is_packed) BitOutStream(endian, Stream.Error) else *Stream, + + pub const Stream = OutStream(Error); + + pub fn init(out_stream: *Stream) Self { + return Self{ .out_stream = switch (is_packed) { + true => BitOutStream(endian, Stream.Error).init(out_stream), + else => out_stream, + } }; + } + + /// Flushes any unwritten bits to the stream + pub fn flush(self: *Self) Stream.Error!void { + if (is_packed) return self.out_stream.flushBits(); + } + + fn serializeInt(self: *Self, value: var) !void { + const T = @typeOf(value); + debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + + const t_bit_count = comptime meta.bitCount(T); + const u8_bit_count = comptime meta.bitCount(u8); + + const U = @IntType(false, t_bit_count); + const Log2U = math.Log2Int(U); + const int_size = @sizeOf(U); + + const u_value = @bitCast(U, value); + + if (is_packed) return self.out_stream.writeBits(u_value, t_bit_count); + + var buffer: [int_size]u8 = undefined; + if (int_size == 1) buffer[0] = u_value; + + for (buffer) |*byte, i| { + const idx = switch (endian) { + builtin.Endian.Big => int_size - i - 1, + builtin.Endian.Little => i, + }; + const shift = @intCast(Log2U, idx * u8_bit_count); + const v = u_value >> shift; + byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); + } + + try self.out_stream.write(buffer); + } + + /// Serializes the passed value into the stream + pub fn serialize(self: *Self, value: var) !void { + const T = comptime @typeOf(value); + + if (comptime trait.isIndexable(T)) { + for (value) |v| + try self.serialize(v); + return; + } + + //custom serializer: fn(self: *const Self, serializer: var) !void + if (comptime trait.hasFn("serialize")(T)) return value.serialize(self); + + if (comptime trait.isPacked(T) and !is_packed) { + var packed_serializer = Serializer(endian, true, Error).init(self.out_stream); + try packed_serializer.serialize(value); + try packed_serializer.flush(); + return; + } + + switch (@typeId(T)) { + builtin.TypeId.Void => return, + builtin.TypeId.Bool => try self.serializeInt(u1(@boolToInt(value))), + builtin.TypeId.Float, builtin.TypeId.Int => try self.serializeInt(value), + builtin.TypeId.Struct => { + const info = @typeInfo(T); + + inline for (info.Struct.fields) |*field_info| { + const name = field_info.name; + const FieldType = field_info.field_type; + + if (FieldType == void or FieldType == u0) continue; + + //It doesn't make sense to write pointers + if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { + @compileError("Will not " ++ "serialize field " ++ name ++ + " of struct " ++ @typeName(T) ++ " because it " ++ + "is of pointer-type " ++ @typeName(FieldType) ++ "."); + } + try self.serialize(@field(value, name)); + } + }, + builtin.TypeId.Union => { + const info = @typeInfo(T).Union; + if (info.tag_type) |TagType| { + const active_tag = meta.activeTag(value); + try self.serialize(active_tag); + //This inline loop is necessary because active_tag is a runtime + // value, but @field requires a comptime value. Our alternative + // is to check each field for a match + inline for (info.fields) |field_info| { + if (field_info.enum_field.?.value == @enumToInt(active_tag)) { + const name = field_info.name; + const FieldType = field_info.field_type; + try self.serialize(@field(value, name)); + return; + } + } + unreachable; + } + @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++ + " because it is an untagged union Use a custom serialize()."); + }, + builtin.TypeId.Optional => { + if (value == null) { + try self.serializeInt(u1(@boolToInt(false))); + return; + } + try self.serializeInt(u1(@boolToInt(true))); + + const OC = comptime meta.Child(T); + + //The way non-pointer optionals are implemented ensures a pointer to them + // will point to the value. The flag is stored at the end of that data. + var val_ptr = @ptrCast(*const OC, &value); + try self.serialize(val_ptr.*); + }, + builtin.TypeId.Enum => { + try self.serializeInt(@enumToInt(value)); + }, + else => @compileError("Cannot serialize " ++ @tagName(@typeId(T)) ++ " types (unimplemented)."), + } + } + }; +} + +test "import io tests" { + comptime { + _ = @import("io_test.zig"); + } +} diff --git a/std/io_test.zig b/std/io_test.zig index 5224199527..fe06a3e2c9 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -1,5 +1,7 @@ const std = @import("index.zig"); const io = std.io; +const meta = std.meta; +const trait = std.trait; const DefaultPrng = std.rand.DefaultPrng; const assert = std.debug.assert; const assertError = std.debug.assertError; @@ -132,3 +134,330 @@ test "SliceOutStream" { assertError(ss.stream.write("Hello world!"), error.OutOfSpace); assert(mem.eql(u8, ss.getWritten(), "Hello worl")); } + +test "BitInStream" { + const mem_be = []u8{ 0b11001101, 0b00001011 }; + const mem_le = []u8{ 0b00011101, 0b10010101 }; + + var mem_in_be = io.SliceInStream.init(mem_be[0..]); + const InError = io.SliceInStream.Error; + var bit_stream_be = io.BitInStream(builtin.Endian.Big, InError).init(&mem_in_be.stream); + + var out_bits: usize = undefined; + + assert(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); + assert(out_bits == 1); + assert(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); + assert(out_bits == 2); + assert(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); + assert(out_bits == 3); + assert(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); + assert(out_bits == 4); + assert(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); + assert(out_bits == 5); + assert(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); + assert(out_bits == 1); + + mem_in_be.pos = 0; + bit_stream_be.bit_count = 0; + assert(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); + assert(out_bits == 15); + + mem_in_be.pos = 0; + bit_stream_be.bit_count = 0; + assert(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); + assert(out_bits == 16); + + _ = try bit_stream_be.readBits(u0, 0, &out_bits); + + var mem_in_le = io.SliceInStream.init(mem_le[0..]); + var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream); + + assert(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); + assert(out_bits == 1); + assert(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); + assert(out_bits == 2); + assert(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); + assert(out_bits == 3); + assert(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); + assert(out_bits == 4); + assert(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); + assert(out_bits == 5); + assert(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); + assert(out_bits == 1); + + mem_in_le.pos = 0; + bit_stream_le.bit_count = 0; + assert(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); + assert(out_bits == 15); + + mem_in_le.pos = 0; + bit_stream_le.bit_count = 0; + assert(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); + assert(out_bits == 16); + + _ = try bit_stream_le.readBits(u0, 0, &out_bits); +} + +test "BitOutStream" { + var mem_be = []u8{0} ** 2; + var mem_le = []u8{0} ** 2; + + var mem_out_be = io.SliceOutStream.init(mem_be[0..]); + const OutError = io.SliceOutStream.Error; + var bit_stream_be = io.BitOutStream(builtin.Endian.Big, OutError).init(&mem_out_be.stream); + + try bit_stream_be.writeBits(u2(1), 1); + try bit_stream_be.writeBits(u5(2), 2); + try bit_stream_be.writeBits(u128(3), 3); + try bit_stream_be.writeBits(u8(4), 4); + try bit_stream_be.writeBits(u9(5), 5); + try bit_stream_be.writeBits(u1(1), 1); + + assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); + + mem_out_be.pos = 0; + + try bit_stream_be.writeBits(u15(0b110011010000101), 15); + try bit_stream_be.flushBits(); + assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); + + mem_out_be.pos = 0; + try bit_stream_be.writeBits(u32(0b110011010000101), 16); + assert(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); + + try bit_stream_be.writeBits(u0(0), 0); + + var mem_out_le = io.SliceOutStream.init(mem_le[0..]); + var bit_stream_le = io.BitOutStream(builtin.Endian.Little, OutError).init(&mem_out_le.stream); + + try bit_stream_le.writeBits(u2(1), 1); + try bit_stream_le.writeBits(u5(2), 2); + try bit_stream_le.writeBits(u128(3), 3); + try bit_stream_le.writeBits(u8(4), 4); + try bit_stream_le.writeBits(u9(5), 5); + try bit_stream_le.writeBits(u1(1), 1); + + assert(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); + + mem_out_le.pos = 0; + try bit_stream_le.writeBits(u15(0b110011010000101), 15); + try bit_stream_le.flushBits(); + assert(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); + + mem_out_le.pos = 0; + try bit_stream_le.writeBits(u32(0b1100110100001011), 16); + assert(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); + + try bit_stream_le.writeBits(u0(0), 0); +} + +fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { + const max_test_bitsize = 17; + + const total_bytes = comptime blk: { + var bytes = 0; + comptime var i = 0; + while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0); + break :blk bytes * 2; + }; + + var data_mem: [total_bytes]u8 = undefined; + var out = io.SliceOutStream.init(data_mem[0..]); + const OutError = io.SliceOutStream.Error; + var out_stream = &out.stream; + var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); + + var in = io.SliceInStream.init(data_mem[0..]); + const InError = io.SliceInStream.Error; + var in_stream = &in.stream; + var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); + + comptime var i = 0; + inline while (i <= max_test_bitsize) : (i += 1) { + const U = @IntType(false, i); + const S = @IntType(true, i); + try serializer.serializeInt(U(i)); + if (i != 0) try serializer.serializeInt(S(-1)); + } + try serializer.flush(); + + i = 0; + inline while (i <= max_test_bitsize) : (i += 1) { + const U = @IntType(false, i); + const S = @IntType(true, i); + const x = try deserializer.deserializeInt(U); + const y = if (i != 0) try deserializer.deserializeInt(S); + assert(x == U(i)); + if (i != 0) assert(y == S(-1)); + } + + const u8_bit_count = comptime meta.bitCount(u8); + //0 + 1 + 2 + ... n = (n * (n + 1)) / 2 + //and we have each for unsigned and signed, so * 2 + const total_bits = (max_test_bitsize * (max_test_bitsize + 1)); + const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0); + const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; + + + + assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); +} + +test "Serializer/Deserializer Int" { + try testIntSerializerDeserializer(builtin.Endian.Big, false); + try testIntSerializerDeserializer(builtin.Endian.Little, false); + try testIntSerializerDeserializer(builtin.Endian.Big, true); + try testIntSerializerDeserializer(builtin.Endian.Little, true); +} + +fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { + const ColorType = enum(u4) { + RGB8 = 1, + RA16 = 2, + R32 = 3, + }; + + const TagAlign = union(enum(u32)) { + A: u8, + B: u8, + C: u8, + }; + + const Color = union(ColorType) { + RGB8: struct { + r: u8, + g: u8, + b: u8, + a: u8, + }, + RA16: struct { + r: u16, + a: u16, + }, + R32: u32, + }; + + const PackedStruct = packed struct { + f_i3: i3, + f_u2: u2, + }; + + //to test custom serialization + const Custom = struct { + f_f16: f16, + f_unused_u32: u32, + + pub fn deserialize(self: *@This(), deserializer: var) !void { + try deserializer.deserializeInto(&self.f_f16); + self.f_unused_u32 = 47; + } + + pub fn serialize(self: *const @This(), serializer: var) !void { + try serializer.serialize(self.f_f16); + } + }; + + const MyStruct = struct { + f_i3: i3, + f_u8: u8, + f_tag_align: TagAlign, + f_u24: u24, + f_i19: i19, + f_void: void, + f_f32: f32, + f_f128: f128, + f_packed_0: PackedStruct, + f_i7arr: [10]i7, + f_of64n: ?f64, + f_of64v: ?f64, + f_color_type: ColorType, + f_packed_1: PackedStruct, + f_custom: Custom, + f_color: Color, + }; + + const my_inst = MyStruct{ + .f_i3 = -1, + .f_u8 = 8, + .f_tag_align = TagAlign{ .B = 148 }, + .f_u24 = 24, + .f_i19 = 19, + .f_void = {}, + .f_f32 = 32.32, + .f_f128 = 128.128, + .f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 }, + .f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + .f_of64n = null, + .f_of64v = 64.64, + .f_color_type = ColorType.R32, + .f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 }, + .f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 }, + .f_color = Color{ .R32 = 123822 }, + }; + + var data_mem: [@sizeOf(MyStruct)]u8 = undefined; + var out = io.SliceOutStream.init(data_mem[0..]); + const OutError = io.SliceOutStream.Error; + var out_stream = &out.stream; + var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); + + var in = io.SliceInStream.init(data_mem[0..]); + const InError = io.SliceInStream.Error; + var in_stream = &in.stream; + var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); + + try serializer.serialize(my_inst); + + const my_copy = try deserializer.deserialize(MyStruct); + + assert(meta.eql(my_copy, my_inst)); +} + +test "Serializer/Deserializer generic" { + try testSerializerDeserializer(builtin.Endian.Big, false); + try testSerializerDeserializer(builtin.Endian.Little, false); + try testSerializerDeserializer(builtin.Endian.Big, true); + try testSerializerDeserializer(builtin.Endian.Little, true); +} + +fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void { + const E = enum(u14) { + One = 1, + Two = 2, + }; + + const A = struct { + e: E, + }; + + const C = union(E) { + One: u14, + Two: f16, + }; + + var data_mem: [4]u8 = undefined; + var out = io.SliceOutStream.init(data_mem[0..]); + const OutError = io.SliceOutStream.Error; + var out_stream = &out.stream; + var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); + + var in = io.SliceInStream.init(data_mem[0..]); + const InError = io.SliceInStream.Error; + var in_stream = &in.stream; + var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); + + try serializer.serialize(u14(3)); + assertError(deserializer.deserialize(A), error.InvalidEnumTag); + out.pos = 0; + try serializer.serialize(u14(3)); + try serializer.serialize(u14(88)); + assertError(deserializer.deserialize(C), error.InvalidEnumTag); +} + +test "Deserializer bad data" { + try testBadData(builtin.Endian.Big, false); + try testBadData(builtin.Endian.Little, false); + try testBadData(builtin.Endian.Big, true); + try testBadData(builtin.Endian.Little, true); +} \ No newline at end of file diff --git a/std/meta/index.zig b/std/meta/index.zig index 69a3097288..4d195a6a12 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -95,7 +95,7 @@ test "std.meta.stringToEnum" { debug.assert(null == stringToEnum(E1, "C")); } -pub fn bitCount(comptime T: type) u32 { +pub fn bitCount(comptime T: type) comptime_int { return switch (@typeInfo(T)) { TypeId.Int => |info| info.bits, TypeId.Float => |info| info.bits, @@ -108,7 +108,7 @@ test "std.meta.bitCount" { debug.assert(bitCount(f32) == 32); } -pub fn alignment(comptime T: type) u29 { +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; @@ -386,6 +386,33 @@ test "std.meta.activeTag" { debug.assert(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); + debug.assert(trait.is(builtin.TypeId.Union)(U)); + debug.assert(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; + debug.assert(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 { @@ -439,6 +466,11 @@ pub fn eql(a: var, b: @typeOf(a)) bool { 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, } } @@ -452,7 +484,7 @@ test "std.meta.eql" { const U = union(enum) { s: S, - f: f32, + f: ?f32, }; const s_1 = S{ diff --git a/std/meta/trait.zig b/std/meta/trait.zig index caf7f1be04..c9d9e971c9 100644 --- a/std/meta/trait.zig +++ b/std/meta/trait.zig @@ -231,6 +231,37 @@ test "std.meta.trait.isPacked" { debug.assert(!isPacked(u8)); } +/// +pub fn isUnsignedInt(comptime T: type) bool { + return switch (@typeId(T)) { + builtin.TypeId.Int => !@typeInfo(T).Int.is_signed, + else => false, + }; +} + +test "isUnsignedInt" { + debug.assert(isUnsignedInt(u32) == true); + debug.assert(isUnsignedInt(comptime_int) == false); + debug.assert(isUnsignedInt(i64) == false); + debug.assert(isUnsignedInt(f64) == false); +} + +/// +pub fn isSignedInt(comptime T: type) bool { + return switch (@typeId(T)) { + builtin.TypeId.ComptimeInt => true, + builtin.TypeId.Int => @typeInfo(T).Int.is_signed, + else => false, + }; +} + +test "isSignedInt" { + debug.assert(isSignedInt(u32) == false); + debug.assert(isSignedInt(comptime_int) == true); + debug.assert(isSignedInt(i64) == true); + debug.assert(isSignedInt(f64) == false); +} + /// pub fn isSingleItemPtr(comptime T: type) bool { if (comptime is(builtin.TypeId.Pointer)(T)) { From b6489ff90afffcf0c69490efcb5941f3bb42fc3c Mon Sep 17 00:00:00 2001 From: tgschultz Date: Fri, 23 Nov 2018 22:29:40 -0600 Subject: [PATCH 013/218] Increased range of bitwidths tested by "serialize/deserialize Int" tests. Added tests for float inf and NaN. --- std/io.zig | 7 +++++- std/io_test.zig | 62 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/std/io.zig b/std/io.zig index 219db124a0..499422fdcc 100644 --- a/std/io.zig +++ b/std/io.zig @@ -1050,8 +1050,13 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ else => in_stream, } }; } + + pub fn alignToByte(self: *Self) void { + if(!is_packed) return; + self.in_stream.alignToByte(); + } - //@BUG: inferred error issue + //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); diff --git a/std/io_test.zig b/std/io_test.zig index fe06a3e2c9..430c8f135a 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -253,7 +253,8 @@ test "BitOutStream" { } fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { - const max_test_bitsize = 17; + //@NOTE: if this test is taking too long, reduce the maximum tested bitsize + const max_test_bitsize = 128; const total_bytes = comptime blk: { var bytes = 0; @@ -278,7 +279,7 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const U = @IntType(false, i); const S = @IntType(true, i); try serializer.serializeInt(U(i)); - if (i != 0) try serializer.serializeInt(S(-1)); + if (i != 0) try serializer.serializeInt(S(-1)) else try serializer.serialize(S(0)); } try serializer.flush(); @@ -287,9 +288,9 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const U = @IntType(false, i); const S = @IntType(true, i); const x = try deserializer.deserializeInt(U); - const y = if (i != 0) try deserializer.deserializeInt(S); + const y = try deserializer.deserializeInt(S); assert(x == U(i)); - if (i != 0) assert(y == S(-1)); + if (i != 0) assert(y == S(-1)) else assert(y == 0); } const u8_bit_count = comptime meta.bitCount(u8); @@ -299,8 +300,6 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0); const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; - - assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); } @@ -311,6 +310,56 @@ test "Serializer/Deserializer Int" { try testIntSerializerDeserializer(builtin.Endian.Little, true); } +fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian, + comptime is_packed: bool) !void +{ + const mem_size = (16*2 + 32*2 + 64*2 + 128*2) / comptime meta.bitCount(u8); + var data_mem: [mem_size]u8 = undefined; + + var out = io.SliceOutStream.init(data_mem[0..]); + const OutError = io.SliceOutStream.Error; + var out_stream = &out.stream; + var serializer = io.Serializer(endian, is_packed, OutError).init(out_stream); + + var in = io.SliceInStream.init(data_mem[0..]); + const InError = io.SliceInStream.Error; + var in_stream = &in.stream; + var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); + + //@TODO: isInf/isNan not currently implemented for f128. + try serializer.serialize(std.math.nan(f16)); + try serializer.serialize(std.math.inf(f16)); + try serializer.serialize(std.math.nan(f32)); + try serializer.serialize(std.math.inf(f32)); + try serializer.serialize(std.math.nan(f64)); + try serializer.serialize(std.math.inf(f64)); + //try serializer.serialize(std.math.nan(f128)); + //try serializer.serialize(std.math.inf(f128)); + const nan_check_f16 = try deserializer.deserialize(f16); + const inf_check_f16 = try deserializer.deserialize(f16); + const nan_check_f32 = try deserializer.deserialize(f32); + const inf_check_f32 = try deserializer.deserialize(f32); + const nan_check_f64 = try deserializer.deserialize(f64); + const inf_check_f64 = try deserializer.deserialize(f64); + //const nan_check_f128 = try deserializer.deserialize(f128); + //const inf_check_f128 = try deserializer.deserialize(f128); + assert(std.math.isNan(nan_check_f16)); + assert(std.math.isInf(inf_check_f16)); + assert(std.math.isNan(nan_check_f32)); + assert(std.math.isInf(inf_check_f32)); + assert(std.math.isNan(nan_check_f64)); + assert(std.math.isInf(inf_check_f64)); + //assert(std.math.isNan(nan_check_f128)); + //assert(std.math.isInf(inf_check_f128)); +} + +test "Serializer/Deserializer Int: Inf/NaN" { + try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, false); + try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, false); + try testIntSerializerDeserializerInfNaN(builtin.Endian.Big, true); + try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true); +} + fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { const ColorType = enum(u4) { RGB8 = 1, @@ -410,7 +459,6 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe try serializer.serialize(my_inst); const my_copy = try deserializer.deserialize(MyStruct); - assert(meta.eql(my_copy, my_inst)); } From 5936bdf8a4163d0c75444e5c8554316de63e3864 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Fri, 30 Nov 2018 14:31:08 -0600 Subject: [PATCH 014/218] Fixed readBits to cast errors to the correct errorset. See #1810 for why this wasn't caught earlier. --- std/io.zig | 4 +++- std/io_test.zig | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/std/io.zig b/std/io.zig index 499422fdcc..5f710a5033 100644 --- a/std/io.zig +++ b/std/io.zig @@ -526,7 +526,9 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { if (err == error.EndOfStream) { return @intCast(U, out_buffer); } - return err; + //@BUG: See #1810. Not sure if the bug is that I have to do this for some + // streams, or that I don't for streams with emtpy errorsets. + return @errSetCast(Error, err); }; switch (endian) { diff --git a/std/io_test.zig b/std/io_test.zig index 430c8f135a..ed8e0fcadb 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -169,6 +169,10 @@ test "BitInStream" { assert(out_bits == 16); _ = try bit_stream_be.readBits(u0, 0, &out_bits); + + assert(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); + assert(out_bits == 0); + assertError(bit_stream_be.readBitsNoEof(u1, 1), error.EndOfStream); var mem_in_le = io.SliceInStream.init(mem_le[0..]); var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream); @@ -197,6 +201,10 @@ test "BitInStream" { assert(out_bits == 16); _ = try bit_stream_le.readBits(u0, 0, &out_bits); + + assert(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); + assert(out_bits == 0); + assertError(bit_stream_le.readBitsNoEof(u1, 1), error.EndOfStream); } test "BitOutStream" { From 8423bd423b7a8cf32246f9d27a400a2cf14ce770 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Fri, 30 Nov 2018 15:02:10 -0600 Subject: [PATCH 015/218] Added explicit test for #1810 issue to io_test.zig. --- std/io_test.zig | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/std/io_test.zig b/std/io_test.zig index ed8e0fcadb..71d46b0874 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -260,6 +260,54 @@ test "BitOutStream" { try bit_stream_le.writeBits(u0(0), 0); } +test "BitStreams with File Stream" { + const tmp_file_name = "temp_test_file.txt"; + { + var file = try os.File.openWrite(tmp_file_name); + defer file.close(); + + var file_out = file.outStream(); + var file_out_stream = &file_out.stream; + const OutError = os.File.WriteError; + var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream); + + try bit_stream.writeBits(u2(1), 1); + try bit_stream.writeBits(u5(2), 2); + try bit_stream.writeBits(u128(3), 3); + try bit_stream.writeBits(u8(4), 4); + try bit_stream.writeBits(u9(5), 5); + try bit_stream.writeBits(u1(1), 1); + try bit_stream.flushBits(); + } + { + var file = try os.File.openRead(tmp_file_name); + defer file.close(); + + var file_in = file.inStream(); + var file_in_stream = &file_in.stream; + const InError = os.File.ReadError; + var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream); + + var out_bits: usize = undefined; + + assert(1 == try bit_stream.readBits(u2, 1, &out_bits)); + assert(out_bits == 1); + assert(2 == try bit_stream.readBits(u5, 2, &out_bits)); + assert(out_bits == 2); + assert(3 == try bit_stream.readBits(u128, 3, &out_bits)); + assert(out_bits == 3); + assert(4 == try bit_stream.readBits(u8, 4, &out_bits)); + assert(out_bits == 4); + assert(5 == try bit_stream.readBits(u9, 5, &out_bits)); + assert(out_bits == 5); + assert(1 == try bit_stream.readBits(u1, 1, &out_bits)); + assert(out_bits == 1); + + assertError(bit_stream.readBitsNoEof(u1, 1), error.EndOfStream); + } + try os.deleteFile(tmp_file_name); +} + fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { //@NOTE: if this test is taking too long, reduce the maximum tested bitsize const max_test_bitsize = 128; From 1188da926ff4cddd5818d85d45b087f6207dfef9 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Sun, 9 Dec 2018 20:52:16 -0600 Subject: [PATCH 016/218] Minor change to custom (de)serializer to allow them to be defined outside of the struct and aliased inside it. This will enable alternate generic serializers (i.e. one that follows pointers) on a struct-by-struct basis. --- std/io.zig | 6 +++--- std/io_test.zig | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/std/io.zig b/std/io.zig index 5f710a5033..c397ff6ede 100644 --- a/std/io.zig +++ b/std/io.zig @@ -1146,7 +1146,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ const child_type_id = @typeId(C); //custom deserializer: fn(self: *Self, deserializer: var) !void - if (comptime trait.hasFn("deserialize")(C)) return ptr.deserialize(self); + if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self); if (comptime trait.isPacked(C) and !is_packed) { var packed_deserializer = Deserializer(endian, true, Error).init(self.in_stream); @@ -1308,8 +1308,8 @@ pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) return; } - //custom serializer: fn(self: *const Self, serializer: var) !void - if (comptime trait.hasFn("serialize")(T)) return value.serialize(self); + //custom serializer: fn(self: Self, serializer: var) !void + if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self); if (comptime trait.isPacked(T) and !is_packed) { var packed_serializer = Serializer(endian, true, Error).init(self.out_stream); diff --git a/std/io_test.zig b/std/io_test.zig index 71d46b0874..0bee0ddaf0 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -416,6 +416,10 @@ test "Serializer/Deserializer Int: Inf/NaN" { try testIntSerializerDeserializerInfNaN(builtin.Endian.Little, true); } +fn testAlternateSerializer(self: var, serializer: var) !void { + try serializer.serialize(self.f_f16); +} + fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packed: bool) !void { const ColorType = enum(u4) { RGB8 = 1, @@ -448,6 +452,8 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe f_u2: u2, }; + + //to test custom serialization const Custom = struct { f_f16: f16, @@ -458,9 +464,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe self.f_unused_u32 = 47; } - pub fn serialize(self: *const @This(), serializer: var) !void { - try serializer.serialize(self.f_f16); - } + pub const serialize = testAlternateSerializer; }; const MyStruct = struct { From 1a8570403f070933842db7739e7139779b7e04a5 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Sun, 9 Dec 2018 20:59:51 -0600 Subject: [PATCH 017/218] Minor doc-comment fix. --- std/io.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/io.zig b/std/io.zig index c397ff6ede..7184787b29 100644 --- a/std/io.zig +++ b/std/io.zig @@ -1243,7 +1243,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ /// endianess, after which data will resume being written at the next byte boundary. /// Types may implement a custom serialization routine with a /// function named `serialize` in the form of: -/// pub fn serialize(self: *const Self, serializer: var) !void +/// pub fn serialize(self: Self, serializer: var) !void /// which will be called when the serializer is used to serialize that type. It will /// pass a const pointer to the type instance to be serialized and a pointer /// to the serializer struct. From 634d11ab28839ebc3caae2bf18cbc028a7a1c3e9 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 5 Dec 2018 16:50:33 -0800 Subject: [PATCH 018/218] Add add compiler_rt routines for float to signed integer conversion And add std.math.f128_* constants. The routines are: __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixtfdi, __fixtfsi, __fixtfti. These all call fixint which is a generic zig function that does the conversion: pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t There are also a set tests: __fixdfdi_test, __fixdfsi_test, __fixdfti_test, __fixsfdi_test, __fixsfsi_test, __fixsfti_test, __fixtfdi_test, __fixtfsi_test, __fixtfti_test. --- CMakeLists.txt | 10 ++ std/math/index.zig | 7 ++ std/special/compiler_rt/fixdfdi.zig | 11 ++ std/special/compiler_rt/fixdfdi_test.zig | 66 ++++++++++ std/special/compiler_rt/fixdfsi.zig | 11 ++ std/special/compiler_rt/fixdfsi_test.zig | 74 +++++++++++ std/special/compiler_rt/fixdfti.zig | 11 ++ std/special/compiler_rt/fixdfti_test.zig | 66 ++++++++++ std/special/compiler_rt/fixint.zig | 74 +++++++++++ std/special/compiler_rt/fixint_test.zig | 152 +++++++++++++++++++++++ std/special/compiler_rt/fixsfdi.zig | 11 ++ std/special/compiler_rt/fixsfdi_test.zig | 68 ++++++++++ std/special/compiler_rt/fixsfsi.zig | 11 ++ std/special/compiler_rt/fixsfsi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixsfti.zig | 11 ++ std/special/compiler_rt/fixsfti_test.zig | 84 +++++++++++++ std/special/compiler_rt/fixtfdi.zig | 11 ++ std/special/compiler_rt/fixtfdi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixtfsi.zig | 11 ++ std/special/compiler_rt/fixtfsi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixtfti.zig | 11 ++ std/special/compiler_rt/fixtfti_test.zig | 66 ++++++++++ std/special/compiler_rt/index.zig | 10 ++ 23 files changed, 1004 insertions(+) create mode 100644 std/special/compiler_rt/fixdfdi.zig create mode 100644 std/special/compiler_rt/fixdfdi_test.zig create mode 100644 std/special/compiler_rt/fixdfsi.zig create mode 100644 std/special/compiler_rt/fixdfsi_test.zig create mode 100644 std/special/compiler_rt/fixdfti.zig create mode 100644 std/special/compiler_rt/fixdfti_test.zig create mode 100644 std/special/compiler_rt/fixint.zig create mode 100644 std/special/compiler_rt/fixint_test.zig create mode 100644 std/special/compiler_rt/fixsfdi.zig create mode 100644 std/special/compiler_rt/fixsfdi_test.zig create mode 100644 std/special/compiler_rt/fixsfsi.zig create mode 100644 std/special/compiler_rt/fixsfsi_test.zig create mode 100644 std/special/compiler_rt/fixsfti.zig create mode 100644 std/special/compiler_rt/fixsfti_test.zig create mode 100644 std/special/compiler_rt/fixtfdi.zig create mode 100644 std/special/compiler_rt/fixtfdi_test.zig create mode 100644 std/special/compiler_rt/fixtfsi.zig create mode 100644 std/special/compiler_rt/fixtfsi_test.zig create mode 100644 std/special/compiler_rt/fixtfti.zig create mode 100644 std/special/compiler_rt/fixtfti_test.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 0817c09f2a..1b64bcca81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -623,6 +623,16 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/fixint.zig" + "special/compiler_rt/fixdfdi.zig" + "special/compiler_rt/fixdfsi.zig" + "special/compiler_rt/fixdfti.zig" + "special/compiler_rt/fixsfdi.zig" + "special/compiler_rt/fixsfsi.zig" + "special/compiler_rt/fixsfti.zig" + "special/compiler_rt/fixtfdi.zig" + "special/compiler_rt/fixtfsi.zig" + "special/compiler_rt/fixtfti.zig" "special/compiler_rt/floattidf.zig" "special/compiler_rt/floattisf.zig" "special/compiler_rt/floattitf.zig" diff --git a/std/math/index.zig b/std/math/index.zig index 83bd2310d0..f37de2505b 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -6,6 +6,13 @@ const assert = std.debug.assert; 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; diff --git a/std/special/compiler_rt/fixdfdi.zig b/std/special/compiler_rt/fixdfdi.zig new file mode 100644 index 0000000000..c108fd15aa --- /dev/null +++ b/std/special/compiler_rt/fixdfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfdi(a: f64) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i64, a); +} + +test "import fixdfdi" { + _ = @import("fixdfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/std/special/compiler_rt/fixdfdi_test.zig new file mode 100644 index 0000000000..72bcf452d2 --- /dev/null +++ b/std/special/compiler_rt/fixdfdi_test.zig @@ -0,0 +1,66 @@ +const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfdi(a: f64, expected: i64) void { + const x = __fixdfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixdfdi" { + //warn("\n"); + + test__fixdfdi(-math.f64_max, math.minInt(i64)); + + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfdi(-2.01, -2); + test__fixdfdi(-2.0, -2); + test__fixdfdi(-1.99, -1); + test__fixdfdi(-1.0, -1); + test__fixdfdi(-0.99, 0); + test__fixdfdi(-0.5, 0); + test__fixdfdi(-math.f64_min, 0); + test__fixdfdi(0.0, 0); + test__fixdfdi(math.f64_min, 0); + test__fixdfdi(0.5, 0); + test__fixdfdi(0.99, 0); + test__fixdfdi(1.0, 1); + test__fixdfdi(1.5, 1); + test__fixdfdi(1.99, 1); + test__fixdfdi(2.0, 2); + test__fixdfdi(2.01, 2); + + test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixdfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixdfsi.zig b/std/special/compiler_rt/fixdfsi.zig new file mode 100644 index 0000000000..83a17b2b0d --- /dev/null +++ b/std/special/compiler_rt/fixdfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfsi(a: f64) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i32, a); +} + +test "import fixdfsi" { + _ = @import("fixdfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/std/special/compiler_rt/fixdfsi_test.zig new file mode 100644 index 0000000000..147f46534a --- /dev/null +++ b/std/special/compiler_rt/fixdfsi_test.zig @@ -0,0 +1,74 @@ +const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfsi(a: f64, expected: i32) void { + const x = __fixdfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixdfsi" { + //warn("\n"); + + test__fixdfsi(-math.f64_max, math.minInt(i32)); + + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixdfsi(-0x1.000000p+31, -0x80000000); + test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + + test__fixdfsi(-2.01, -2); + test__fixdfsi(-2.0, -2); + test__fixdfsi(-1.99, -1); + test__fixdfsi(-1.0, -1); + test__fixdfsi(-0.99, 0); + test__fixdfsi(-0.5, 0); + test__fixdfsi(-math.f64_min, 0); + test__fixdfsi(0.0, 0); + test__fixdfsi(math.f64_min, 0); + test__fixdfsi(0.5, 0); + test__fixdfsi(0.99, 0); + test__fixdfsi(1.0, 1); + test__fixdfsi(1.5, 1); + test__fixdfsi(1.99, 1); + test__fixdfsi(2.0, 2); + test__fixdfsi(2.01, 2); + + test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixdfsi(math.f64_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixdfti.zig b/std/special/compiler_rt/fixdfti.zig new file mode 100644 index 0000000000..e30f885cf6 --- /dev/null +++ b/std/special/compiler_rt/fixdfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfti(a: f64) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i128, a); +} + +test "import fixdfti" { + _ = @import("fixdfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfti_test.zig b/std/special/compiler_rt/fixdfti_test.zig new file mode 100644 index 0000000000..5bb3a31a3f --- /dev/null +++ b/std/special/compiler_rt/fixdfti_test.zig @@ -0,0 +1,66 @@ +const __fixdfti = @import("fixdfti.zig").__fixdfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfti(a: f64, expected: i128) void { + const x = __fixdfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixdfti" { + //warn("\n"); + + test__fixdfti(-math.f64_max, math.minInt(i128)); + + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfti(-2.01, -2); + test__fixdfti(-2.0, -2); + test__fixdfti(-1.99, -1); + test__fixdfti(-1.0, -1); + test__fixdfti(-0.99, 0); + test__fixdfti(-0.5, 0); + test__fixdfti(-math.f64_min, 0); + test__fixdfti(0.0, 0); + test__fixdfti(math.f64_min, 0); + test__fixdfti(0.5, 0); + test__fixdfti(0.99, 0); + test__fixdfti(1.0, 1); + test__fixdfti(1.5, 1); + test__fixdfti(1.99, 1); + test__fixdfti(2.0, 2); + test__fixdfti(2.01, 2); + + test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixdfti(math.f64_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixint.zig b/std/special/compiler_rt/fixint.zig new file mode 100644 index 0000000000..fd31798cc2 --- /dev/null +++ b/std/special/compiler_rt/fixint.zig @@ -0,0 +1,74 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const Log2Int = std.math.Log2Int; +const maxInt = std.math.maxInt; +const minInt = std.math.minInt; + +const DBG = false; + +pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { + @setRuntimeSafety(is_test); + + const rep_t = switch (fp_t) { + f32 => u32, + f64 => u64, + f128 => u128, + else => unreachable, + }; + const significandBits = switch (fp_t) { + f32 => 23, + f64 => 52, + f128 => 112, + else => unreachable, + }; + + const typeWidth = rep_t.bit_count; + const exponentBits = (typeWidth - significandBits - 1); + const signBit = (rep_t(1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const implicitBit = (rep_t(1) << significandBits); + const significandMask = (implicitBit - 1); + + // Break a into sign, exponent, significand + const aRep: rep_t = @bitCast(rep_t, a); + const absMask = signBit - 1; + const aAbs: rep_t = aRep & absMask; + + const negative = (aRep & signBit) != 0; + const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias; + const significand: rep_t = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the uint_result is zero. + if (exponent < 0) return 0; + + // The unsigned result needs to be large enough to handle an fixint_t or rep_t + const fixuint_t = @IntType(false, fixint_t.bit_count); + const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t; + var uint_result: UintResultType = undefined; + + // If the value is too large for the integer type, saturate. + if (@intCast(usize, exponent) >= fixint_t.bit_count) { + return if (negative) fixint_t(minInt(fixint_t)) else fixint_t(maxInt(fixint_t)); + } + + // If 0 <= exponent < significandBits, right shift else left shift + if (exponent < significandBits) { + uint_result = @intCast(UintResultType, significand) >> @intCast(Log2Int(UintResultType), significandBits - exponent); + } else { + uint_result = @intCast(UintResultType, significand) << @intCast(Log2Int(UintResultType), exponent - significandBits); + } + + // Cast to final signed result + if (negative) { + return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result); + } else { + return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result); + } +} + +test "import fixint" { + _ = @import("fixint_test.zig"); +} diff --git a/std/special/compiler_rt/fixint_test.zig b/std/special/compiler_rt/fixint_test.zig new file mode 100644 index 0000000000..6676bddbee --- /dev/null +++ b/std/special/compiler_rt/fixint_test.zig @@ -0,0 +1,152 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +const fixint = @import("fixint.zig").fixint; + +fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void { + const x = fixint(fp_t, fixint_t, a); + //warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected); + assert(x == expected); +} + +test "fixint.i1" { + test__fixint(f32, i1, -math.inf_f32, -1); + test__fixint(f32, i1, -math.f32_max, -1); + test__fixint(f32, i1, -2.0, -1); + test__fixint(f32, i1, -1.1, -1); + test__fixint(f32, i1, -1.0, -1); + test__fixint(f32, i1, -0.9, 0); + test__fixint(f32, i1, -0.1, 0); + test__fixint(f32, i1, -math.f32_min, 0); + test__fixint(f32, i1, -0.0, 0); + test__fixint(f32, i1, 0.0, 0); + test__fixint(f32, i1, math.f32_min, 0); + test__fixint(f32, i1, 0.1, 0); + test__fixint(f32, i1, 0.9, 0); + test__fixint(f32, i1, 1.0, 0); + test__fixint(f32, i1, 2.0, 0); + test__fixint(f32, i1, math.f32_max, 0); + test__fixint(f32, i1, math.inf_f32, 0); +} + +test "fixint.i2" { + test__fixint(f32, i2, -math.inf_f32, -2); + test__fixint(f32, i2, -math.f32_max, -2); + test__fixint(f32, i2, -2.0, -2); + test__fixint(f32, i2, -1.9, -1); + test__fixint(f32, i2, -1.1, -1); + test__fixint(f32, i2, -1.0, -1); + test__fixint(f32, i2, -0.9, 0); + test__fixint(f32, i2, -0.1, 0); + test__fixint(f32, i2, -math.f32_min, 0); + test__fixint(f32, i2, -0.0, 0); + test__fixint(f32, i2, 0.0, 0); + test__fixint(f32, i2, math.f32_min, 0); + test__fixint(f32, i2, 0.1, 0); + test__fixint(f32, i2, 0.9, 0); + test__fixint(f32, i2, 1.0, 1); + test__fixint(f32, i2, 2.0, 1); + test__fixint(f32, i2, math.f32_max, 1); + test__fixint(f32, i2, math.inf_f32, 1); +} + +test "fixint.i3" { + test__fixint(f32, i3, -math.inf_f32, -4); + test__fixint(f32, i3, -math.f32_max, -4); + test__fixint(f32, i3, -4.0, -4); + test__fixint(f32, i3, -3.0, -3); + test__fixint(f32, i3, -2.0, -2); + test__fixint(f32, i3, -1.9, -1); + test__fixint(f32, i3, -1.1, -1); + test__fixint(f32, i3, -1.0, -1); + test__fixint(f32, i3, -0.9, 0); + test__fixint(f32, i3, -0.1, 0); + test__fixint(f32, i3, -math.f32_min, 0); + test__fixint(f32, i3, -0.0, 0); + test__fixint(f32, i3, 0.0, 0); + test__fixint(f32, i3, math.f32_min, 0); + test__fixint(f32, i3, 0.1, 0); + test__fixint(f32, i3, 0.9, 0); + test__fixint(f32, i3, 1.0, 1); + test__fixint(f32, i3, 2.0, 2); + test__fixint(f32, i3, 3.0, 3); + test__fixint(f32, i3, 4.0, 3); + test__fixint(f32, i3, math.f32_max, 3); + test__fixint(f32, i3, math.inf_f32, 3); +} + +test "fixint.i32" { + test__fixint(f64, i32, -math.inf_f64, math.minInt(i32)); + test__fixint(f64, i32, -math.f64_max, math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32)), math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32))+1, math.minInt(i32)+1); + test__fixint(f64, i32, -2.0, -2); + test__fixint(f64, i32, -1.9, -1); + test__fixint(f64, i32, -1.1, -1); + test__fixint(f64, i32, -1.0, -1); + test__fixint(f64, i32, -0.9, 0); + test__fixint(f64, i32, -0.1, 0); + test__fixint(f64, i32, -math.f32_min, 0); + test__fixint(f64, i32, -0.0, 0); + test__fixint(f64, i32, 0.0, 0); + test__fixint(f64, i32, math.f32_min, 0); + test__fixint(f64, i32, 0.1, 0); + test__fixint(f64, i32, 0.9, 0); + test__fixint(f64, i32, 1.0, 1); + test__fixint(f64, i32, f64(math.maxInt(i32))-1, math.maxInt(i32)-1); + test__fixint(f64, i32, f64(math.maxInt(i32)), math.maxInt(i32)); + test__fixint(f64, i32, math.f64_max, math.maxInt(i32)); + test__fixint(f64, i32, math.inf_f64, math.maxInt(i32)); +} + +test "fixint.i64" { + test__fixint(f64, i64, -math.inf_f64, math.minInt(i64)); + test__fixint(f64, i64, -math.f64_max, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)), math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64))+1, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)/2), math.minInt(i64)/2); + test__fixint(f64, i64, -2.0, -2); + test__fixint(f64, i64, -1.9, -1); + test__fixint(f64, i64, -1.1, -1); + test__fixint(f64, i64, -1.0, -1); + test__fixint(f64, i64, -0.9, 0); + test__fixint(f64, i64, -0.1, 0); + test__fixint(f64, i64, -math.f32_min, 0); + test__fixint(f64, i64, -0.0, 0); + test__fixint(f64, i64, 0.0, 0); + test__fixint(f64, i64, math.f32_min, 0); + test__fixint(f64, i64, 0.1, 0); + test__fixint(f64, i64, 0.9, 0); + test__fixint(f64, i64, 1.0, 1); + test__fixint(f64, i64, f64(math.maxInt(i64))-1, math.maxInt(i64)); + test__fixint(f64, i64, f64(math.maxInt(i64)), math.maxInt(i64)); + test__fixint(f64, i64, math.f64_max, math.maxInt(i64)); + test__fixint(f64, i64, math.inf_f64, math.maxInt(i64)); +} + +test "fixint.i128" { + test__fixint(f64, i128, -math.inf_f64, math.minInt(i128)); + test__fixint(f64, i128, -math.f64_max, math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128)), math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128))+1, math.minInt(i128)); + test__fixint(f64, i128, -2.0, -2); + test__fixint(f64, i128, -1.9, -1); + test__fixint(f64, i128, -1.1, -1); + test__fixint(f64, i128, -1.0, -1); + test__fixint(f64, i128, -0.9, 0); + test__fixint(f64, i128, -0.1, 0); + test__fixint(f64, i128, -math.f32_min, 0); + test__fixint(f64, i128, -0.0, 0); + test__fixint(f64, i128, 0.0, 0); + test__fixint(f64, i128, math.f32_min, 0); + test__fixint(f64, i128, 0.1, 0); + test__fixint(f64, i128, 0.9, 0); + test__fixint(f64, i128, 1.0, 1); + test__fixint(f64, i128, f64(math.maxInt(i128))-1, math.maxInt(i128)); + test__fixint(f64, i128, f64(math.maxInt(i128)), math.maxInt(i128)); + test__fixint(f64, i128, math.f64_max, math.maxInt(i128)); + test__fixint(f64, i128, math.inf_f64, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixsfdi.zig b/std/special/compiler_rt/fixsfdi.zig new file mode 100644 index 0000000000..ffa81d13ab --- /dev/null +++ b/std/special/compiler_rt/fixsfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfdi(a: f32) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i64, a); +} + +test "import fixsfdi" { + _ = @import("fixsfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/std/special/compiler_rt/fixsfdi_test.zig new file mode 100644 index 0000000000..ef8e50e38e --- /dev/null +++ b/std/special/compiler_rt/fixsfdi_test.zig @@ -0,0 +1,68 @@ +const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfdi(a: f32, expected: i64) void { + const x = __fixsfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixsfdi" { + //warn("\n"); + + test__fixsfdi(-math.f32_max, math.minInt(i64)); + + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfdi(-2.01, -2); + test__fixsfdi(-2.0, -2); + test__fixsfdi(-1.99, -1); + test__fixsfdi(-1.0, -1); + test__fixsfdi(-0.99, 0); + test__fixsfdi(-0.5, 0); + test__fixsfdi(-math.f32_min, 0); + test__fixsfdi(0.0, 0); + test__fixsfdi(math.f32_min, 0); + test__fixsfdi(0.5, 0); + test__fixsfdi(0.99, 0); + test__fixsfdi(1.0, 1); + test__fixsfdi(1.5, 1); + test__fixsfdi(1.99, 1); + test__fixsfdi(2.0, 2); + test__fixsfdi(2.01, 2); + + test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixsfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixsfsi.zig b/std/special/compiler_rt/fixsfsi.zig new file mode 100644 index 0000000000..9a94b4395b --- /dev/null +++ b/std/special/compiler_rt/fixsfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfsi(a: f32) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i32, a); +} + +test "import fixsfsi" { + _ = @import("fixsfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/std/special/compiler_rt/fixsfsi_test.zig new file mode 100644 index 0000000000..d5c0ba5c2a --- /dev/null +++ b/std/special/compiler_rt/fixsfsi_test.zig @@ -0,0 +1,76 @@ +const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfsi(a: f32, expected: i32) void { + const x = __fixsfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixsfsi" { + //warn("\n"); + + test__fixsfsi(-math.f32_max, math.minInt(i32)); + + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixsfsi(-0x1.000000p+31, -0x80000000); + test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfsi(-2.01, -2); + test__fixsfsi(-2.0, -2); + test__fixsfsi(-1.99, -1); + test__fixsfsi(-1.0, -1); + test__fixsfsi(-0.99, 0); + test__fixsfsi(-0.5, 0); + test__fixsfsi(-math.f32_min, 0); + test__fixsfsi(0.0, 0); + test__fixsfsi(math.f32_min, 0); + test__fixsfsi(0.5, 0); + test__fixsfsi(0.99, 0); + test__fixsfsi(1.0, 1); + test__fixsfsi(1.5, 1); + test__fixsfsi(1.99, 1); + test__fixsfsi(2.0, 2); + test__fixsfsi(2.01, 2); + + test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); + test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixsfsi(math.f32_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixsfti.zig b/std/special/compiler_rt/fixsfti.zig new file mode 100644 index 0000000000..806a1678aa --- /dev/null +++ b/std/special/compiler_rt/fixsfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfti(a: f32) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i128, a); +} + +test "import fixsfti" { + _ = @import("fixsfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfti_test.zig b/std/special/compiler_rt/fixsfti_test.zig new file mode 100644 index 0000000000..d693143b18 --- /dev/null +++ b/std/special/compiler_rt/fixsfti_test.zig @@ -0,0 +1,84 @@ +const __fixsfti = @import("fixsfti.zig").__fixsfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfti(a: f32, expected: i128) void { + const x = __fixsfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixsfti" { + //warn("\n"); + + test__fixsfti(-math.f32_max, math.minInt(i128)); + + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfti(-0x1.000000p+31, -0x80000000); + test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfti(-2.01, -2); + test__fixsfti(-2.0, -2); + test__fixsfti(-1.99, -1); + test__fixsfti(-1.0, -1); + test__fixsfti(-0.99, 0); + test__fixsfti(-0.5, 0); + test__fixsfti(-math.f32_min, 0); + test__fixsfti(0.0, 0); + test__fixsfti(math.f32_min, 0); + test__fixsfti(0.5, 0); + test__fixsfti(0.99, 0); + test__fixsfti(1.0, 1); + test__fixsfti(1.5, 1); + test__fixsfti(1.99, 1); + test__fixsfti(2.0, 2); + test__fixsfti(2.01, 2); + + test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfti(0x1.FFFFFFp+30, 0x80000000); + test__fixsfti(0x1.000000p+31, 0x80000000); + + test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixsfti(math.f32_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixtfdi.zig b/std/special/compiler_rt/fixtfdi.zig new file mode 100644 index 0000000000..8d99231b74 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfdi(a: f128) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i64, a); +} + +test "import fixtfdi" { + _ = @import("fixtfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/std/special/compiler_rt/fixtfdi_test.zig new file mode 100644 index 0000000000..58ccbc5832 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi_test.zig @@ -0,0 +1,76 @@ +const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfdi(a: f128, expected: i64) void { + const x = __fixtfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixtfdi" { + //warn("\n"); + + test__fixtfdi(-math.f128_max, math.minInt(i64)); + + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + test__fixtfdi(-0x1.000000p+31, -0x80000000); + test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfdi(-2.01, -2); + test__fixtfdi(-2.0, -2); + test__fixtfdi(-1.99, -1); + test__fixtfdi(-1.0, -1); + test__fixtfdi(-0.99, 0); + test__fixtfdi(-0.5, 0); + test__fixtfdi(-math.f64_min, 0); + test__fixtfdi(0.0, 0); + test__fixtfdi(math.f64_min, 0); + test__fixtfdi(0.5, 0); + test__fixtfdi(0.99, 0); + test__fixtfdi(1.0, 1); + test__fixtfdi(1.5, 1); + test__fixtfdi(1.99, 1); + test__fixtfdi(2.0, 2); + test__fixtfdi(2.01, 2); + + test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfdi(0x1.000000p+31, 0x80000000); + + test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixtfdi(math.f128_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixtfsi.zig b/std/special/compiler_rt/fixtfsi.zig new file mode 100644 index 0000000000..f3f83634b2 --- /dev/null +++ b/std/special/compiler_rt/fixtfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfsi(a: f128) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i32, a); +} + +test "import fixtfsi" { + _ = @import("fixtfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/std/special/compiler_rt/fixtfsi_test.zig new file mode 100644 index 0000000000..7a3cc7f46c --- /dev/null +++ b/std/special/compiler_rt/fixtfsi_test.zig @@ -0,0 +1,76 @@ +const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfsi(a: f128, expected: i32) void { + const x = __fixtfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixtfsi" { + //warn("\n"); + + test__fixtfsi(-math.f128_max, math.minInt(i32)); + + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixtfsi(-0x1.000000p+31, -0x80000000); + test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfsi(-2.01, -2); + test__fixtfsi(-2.0, -2); + test__fixtfsi(-1.99, -1); + test__fixtfsi(-1.0, -1); + test__fixtfsi(-0.99, 0); + test__fixtfsi(-0.5, 0); + test__fixtfsi(-math.f32_min, 0); + test__fixtfsi(0.0, 0); + test__fixtfsi(math.f32_min, 0); + test__fixtfsi(0.5, 0); + test__fixtfsi(0.99, 0); + test__fixtfsi(1.0, 1); + test__fixtfsi(1.5, 1); + test__fixtfsi(1.99, 1); + test__fixtfsi(2.0, 2); + test__fixtfsi(2.01, 2); + + test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixtfsi(math.f128_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixtfti.zig b/std/special/compiler_rt/fixtfti.zig new file mode 100644 index 0000000000..07d38f2c3b --- /dev/null +++ b/std/special/compiler_rt/fixtfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfti(a: f128) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i128, a); +} + +test "import fixtfti" { + _ = @import("fixtfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfti_test.zig b/std/special/compiler_rt/fixtfti_test.zig new file mode 100644 index 0000000000..520009486a --- /dev/null +++ b/std/special/compiler_rt/fixtfti_test.zig @@ -0,0 +1,66 @@ +const __fixtfti = @import("fixtfti.zig").__fixtfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfti(a: f128, expected: i128) void { + const x = __fixtfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixtfti" { + //warn("\n"); + + test__fixtfti(-math.f128_max, math.minInt(i128)); + + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixtfti(-2.01, -2); + test__fixtfti(-2.0, -2); + test__fixtfti(-1.99, -1); + test__fixtfti(-1.0, -1); + test__fixtfti(-0.99, 0); + test__fixtfti(-0.5, 0); + test__fixtfti(-math.f128_min, 0); + test__fixtfti(0.0, 0); + test__fixtfti(math.f128_min, 0); + test__fixtfti(0.5, 0); + test__fixtfti(0.99, 0); + test__fixtfti(1.0, 1); + test__fixtfti(1.5, 1); + test__fixtfti(1.99, 1); + test__fixtfti(2.0, 2); + test__fixtfti(2.01, 2); + + test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixtfti(math.f128_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index b2add4e3fa..4bbfc2b290 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -52,6 +52,16 @@ comptime { @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); From b883bc873df7f1a8fa3a13800402e1ec8da74328 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 Dec 2018 20:19:46 -0500 Subject: [PATCH 019/218] breaking API changes to all readInt/writeInt functions & more * add `@bswap` builtin function. See #767 * comptime evaluation facilities are improved to be able to handle a `@ptrCast` with a backing array. * `@truncate` allows "truncating" a u0 value to any integer type, and the result is always comptime known to be `0`. * when specifying pointer alignment in a type expression, the alignment value of pointers which do not have addresses at runtime is ignored, and always has the default/ABI alignment * threw in a fix to freebsd/x86_64.zig to update syntax from language changes * some improvements are pending #863 closes #638 closes #1733 std lib API changes * io.InStream().readIntNe renamed to readIntNative * io.InStream().readIntLe renamed to readIntLittle * io.InStream().readIntBe renamed to readIntBig * introduced io.InStream().readIntForeign * io.InStream().readInt has parameter order changed * io.InStream().readVarInt has parameter order changed * io.InStream().writeIntNe renamed to writeIntNative * introduced io.InStream().writeIntForeign * io.InStream().writeIntLe renamed to writeIntLittle * io.InStream().writeIntBe renamed to writeIntBig * io.InStream().writeInt has parameter order changed * mem.readInt has different parameters and semantics * introduced mem.readIntNative * introduced mem.readIntForeign * mem.readIntBE renamed to mem.readIntBig and different API * mem.readIntLE renamed to mem.readIntLittle and different API * introduced mem.readIntSliceNative * introduced mem.readIntSliceForeign * introduced mem.readIntSliceLittle * introduced mem.readIntSliceBig * introduced mem.readIntSlice * mem.writeInt has different parameters and semantics * introduced mem.writeIntNative * introduced mem.writeIntForeign * mem.writeIntBE renamed to mem.readIntBig and different semantics * mem.writeIntLE renamed to mem.readIntLittle and different semantics * introduced mem.writeIntSliceForeign * introduced mem.writeIntSliceNative * introduced mem.writeIntSliceBig * introduced mem.writeIntSliceLittle * introduced mem.writeIntSlice * removed mem.endianSwapIfLe * removed mem.endianSwapIfBe * removed mem.endianSwapIf * added mem.littleToNative * added mem.bigToNative * added mem.toNative * added mem.nativeTo * added mem.nativeToLittle * added mem.nativeToBig --- doc/langref.html.in | 9 + example/guess_number/main.zig | 2 +- src-self-hosted/compilation.zig | 2 +- src/all_types.hpp | 13 + src/analyze.cpp | 7 +- src/codegen.cpp | 31 +++ src/ir.cpp | 156 ++++++++++- src/ir_print.cpp | 15 ++ std/coff.zig | 44 +-- std/crypto/blake2.zig | 11 +- std/crypto/chacha20.zig | 53 ++-- std/crypto/md5.zig | 3 +- std/crypto/poly1305.zig | 27 +- std/crypto/sha1.zig | 3 +- std/crypto/sha2.zig | 6 +- std/crypto/sha3.zig | 5 +- std/crypto/x25519.zig | 41 +-- std/debug/index.zig | 60 +++-- std/elf.zig | 70 ++--- std/event/io.zig | 18 +- std/hash/siphash.zig | 14 +- std/heap.zig | 2 +- std/io.zig | 68 +++-- std/mem.zig | 457 +++++++++++++++++++------------- std/net.zig | 12 +- std/os/child_process.zig | 4 +- std/os/freebsd/x86_64.zig | 6 +- std/pdb.zig | 6 +- std/rand/index.zig | 8 +- std/unicode.zig | 30 +-- test/behavior.zig | 2 + test/cases/bswap.zig | 32 +++ test/cases/truncate.zig | 8 + test/compile_errors.zig | 12 + 34 files changed, 818 insertions(+), 419 deletions(-) create mode 100644 test/cases/bswap.zig create mode 100644 test/cases/truncate.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index a1903331a4..f820a05b69 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5312,6 +5312,15 @@ comptime {

{#header_close#} + {#header_open|@bswap#} +
{#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

+

+ Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, + and converts a little endian integer to a big endian integer. +

+ {#header_close#} + {#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}

diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 66264666bc..b4eb1c292a 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -15,7 +15,7 @@ pub fn main() !void { std.debug.warn("unable to seed random number generator: {}", err); return err; }; - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = std.mem.readIntNative(u64, &seed_bytes); var prng = std.rand.DefaultPrng.init(seed); const answer = prng.random.range(u8, 0, 100) + 1; diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index a8c3e13e33..0594cbd749 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -55,7 +55,7 @@ pub const ZigCompiler = struct { var seed_bytes: [@sizeOf(u64)]u8 = undefined; try std.os.getRandomBytes(seed_bytes[0..]); - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = mem.readIntNative(u64, &seed_bytes); return ZigCompiler{ .loop = loop, diff --git a/src/all_types.hpp b/src/all_types.hpp index f7ada09a57..83b7e8495f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,7 @@ enum BuiltinFnId { BuiltinFnIdErrorReturnTrace, BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, + BuiltinFnIdBswap, }; struct BuiltinFnEntry { @@ -1487,6 +1488,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdFloor, ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, + ZigLLVMFnIdBswap, }; enum AddSubMul { @@ -1516,6 +1518,9 @@ struct ZigLLVMFnKey { uint32_t bit_count; bool is_signed; } overflow_arithmetic; + struct { + uint32_t bit_count; + } bswap; } data; }; @@ -2158,6 +2163,7 @@ enum IrInstructionId { IrInstructionIdMergeErrRetTraces, IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, + IrInstructionIdBswap, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3251,6 +3257,13 @@ struct IrInstructionCheckRuntimeScope { IrInstruction *is_comptime; }; +struct IrInstructionBswap { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 2f4b173c5f..46686ce772 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -401,7 +401,8 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { } ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) + bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, + uint32_t bit_offset_in_host, uint32_t host_int_bytes) { assert(!type_is_invalid(child_type)); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); @@ -6110,6 +6111,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; case ZigLLVMFnIdSqrt: return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; + case ZigLLVMFnIdBswap: + return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6128,6 +6131,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.clz.bit_count == b.data.clz.bit_count; case ZigLLVMFnIdPopCount: return a.data.pop_count.bit_count == b.data.pop_count.bit_count; + case ZigLLVMFnIdBswap: + return a.data.bswap.bit_count == b.data.bswap.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/codegen.cpp b/src/codegen.cpp index 1033ed8120..08dd11800a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3814,6 +3814,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdPopCount; key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBswap) { + fn_name = "bswap"; + n_args = 1; + key.id = ZigLLVMFnIdBswap; + key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5098,6 +5103,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + if (int_type->data.integral.bit_count % 16 == 0) { + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); + } + // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate + ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, + int_type->data.integral.bit_count + 8); + // aabbcc + LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, ""); + // 00aabbcc + LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); + LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); + // ccbbaa00 + LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, + LLVMConstInt(extended_type->type_ref, 8, false), ""); + // 00ccbbaa + return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5363,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); } zig_unreachable(); } @@ -6757,6 +6787,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1); create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); + create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 68a0b7f6f6..dc87f040bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -856,6 +856,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { return IrInstructionIdSqrt; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { + return IrInstructionIdBswap; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2705,6 +2709,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc return &instruction->base; } +static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBswap *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -4689,6 +4704,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBswap: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -13674,18 +13704,55 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, return ErrorNone; } - if (dst_size > src_size) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; + if (dst_size <= src_size) { + Buf buf = BUF_INIT; + buf_resize(&buf, src_size); + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); - return ErrorNone; + switch (ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", + dst_size, buf_ptr(&pointee->type->name), src_size)); + return ErrorSemanticAnalyzeFail; + } + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + size_t elem_size = src_size; + src_size = elem_size * + (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + if (dst_size > src_size) { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", + dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, + src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; + } + case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialDiscard: + case ConstPtrSpecialHardCodedAddr: + case ConstPtrSpecialFunction: + zig_panic("TODO"); + } + zig_unreachable(); } static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { @@ -18054,6 +18121,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + if (src_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); @@ -20299,6 +20372,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(child_type)) { + align_bytes = 0; + } } else { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20898,6 +20974,63 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS return result; } +static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + if (int_type->data.integral.bit_count % 8 != 0) { + ir_add_error(ira, instruction->type, + buf_sprintf("@bswap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", + buf_ptr(&int_type->name), int_type->data.integral.bit_count)); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (int_type->data.integral.bit_count == 8) { + return casted_op; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t buf_size = int_type->data.integral.bit_count / 8; + uint8_t *buf = allocate_nonzero(buf_size); + bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); + bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, + int_type->data.integral.is_signed); + return result; + } + + IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; IrInstruction *target = instruction->target->child; @@ -21233,6 +21366,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21454,6 +21589,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdBswap: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 13c06e4e2d..e09b0073eb 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1323,6 +1323,18 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { + fprintf(irp->f, "@bswap("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1736,6 +1748,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSqrt: ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); break; + case IrInstructionIdBswap: + ir_print_bswap(irp, (IrInstructionBswap *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/std/coff.zig b/std/coff.zig index 6a1aa34b46..53bd2a4b7a 100644 --- a/std/coff.zig +++ b/std/coff.zig @@ -51,7 +51,7 @@ pub const Coff = struct { // Seek to PE File Header (coff header) try self.in_file.seekTo(pe_pointer_offset); - const pe_magic_offset = try in.readIntLe(u32); + const pe_magic_offset = try in.readIntLittle(u32); try self.in_file.seekTo(pe_magic_offset); var pe_header_magic: [4]u8 = undefined; @@ -60,13 +60,13 @@ pub const Coff = struct { return error.InvalidPEHeader; self.coff_header = CoffHeader{ - .machine = try in.readIntLe(u16), - .number_of_sections = try in.readIntLe(u16), - .timedate_stamp = try in.readIntLe(u32), - .pointer_to_symbol_table = try in.readIntLe(u32), - .number_of_symbols = try in.readIntLe(u32), - .size_of_optional_header = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u16), + .machine = try in.readIntLittle(u16), + .number_of_sections = try in.readIntLittle(u16), + .timedate_stamp = try in.readIntLittle(u32), + .pointer_to_symbol_table = try in.readIntLittle(u32), + .number_of_symbols = try in.readIntLittle(u32), + .size_of_optional_header = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u16), }; switch (self.coff_header.machine) { @@ -79,7 +79,7 @@ pub const Coff = struct { fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void { const in = &file_stream.stream; - self.pe_header.magic = try in.readIntLe(u16); + self.pe_header.magic = try in.readIntLittle(u16); // For now we're only interested in finding the reference to the .pdb, // so we'll skip most of this header, which size is different in 32 // 64 bits by the way. @@ -93,14 +93,14 @@ pub const Coff = struct { try self.in_file.seekForward(skip_size); - const number_of_rva_and_sizes = try in.readIntLe(u32); + const number_of_rva_and_sizes = try in.readIntLittle(u32); if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return error.InvalidPEHeader; for (self.pe_header.data_directory) |*data_dir| { data_dir.* = OptionalHeader.DataDirectory{ - .virtual_address = try in.readIntLe(u32), - .size = try in.readIntLe(u32), + .virtual_address = try in.readIntLittle(u32), + .size = try in.readIntLittle(u32), }; } } @@ -124,7 +124,7 @@ pub const Coff = struct { if (!mem.eql(u8, cv_signature, "RSDS")) return error.InvalidPEMagic; try in.readNoEof(self.guid[0..]); - self.age = try in.readIntLe(u32); + self.age = try in.readIntLittle(u32); // Finally read the null-terminated string. var byte = try in.readByte(); @@ -157,15 +157,15 @@ pub const Coff = struct { try self.sections.append(Section{ .header = SectionHeader{ .name = name, - .misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) }, - .virtual_address = try in.readIntLe(u32), - .size_of_raw_data = try in.readIntLe(u32), - .pointer_to_raw_data = try in.readIntLe(u32), - .pointer_to_relocations = try in.readIntLe(u32), - .pointer_to_line_numbers = try in.readIntLe(u32), - .number_of_relocations = try in.readIntLe(u16), - .number_of_line_numbers = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u32), + .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) }, + .virtual_address = try in.readIntLittle(u32), + .size_of_raw_data = try in.readIntLittle(u32), + .pointer_to_raw_data = try in.readIntLittle(u32), + .pointer_to_relocations = try in.readIntLittle(u32), + .pointer_to_line_numbers = try in.readIntLittle(u32), + .number_of_relocations = try in.readIntLittle(u16), + .number_of_line_numbers = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u32), }, }); } diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index dc68d806d2..e3de65916a 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } @@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]); + // TODO https://github.com/ziglang/zig/issues/863 + r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); } var k: usize = 0; @@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); } } @@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); } var k: usize = 0; diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 059bc82088..5ec1e79756 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); } } @@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = []u32{ - mem.readIntLE(u32, c[0..4]), - mem.readIntLE(u32, c[4..8]), - mem.readIntLE(u32, c[8..12]), - mem.readIntLE(u32, c[12..16]), + mem.readIntSliceLittle(u32, c[0..4]), + mem.readIntSliceLittle(u32, c[4..8]), + mem.readIntSliceLittle(u32, c[8..12]), + mem.readIntSliceLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntLE(u32, nonce[0..4]); - c[2] = mem.readIntLE(u32, nonce[4..8]); - c[3] = mem.readIntLE(u32, nonce[8..12]); + c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLE(u32, nonce[0..4]); - c[3] = mem.readIntLE(u32, nonce[4..8]); + c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); const big_block = (block_size << 32); diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 8663fa751f..994a7fa25c 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -112,7 +112,8 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index a5d9fcdf57..0d7a4d672d 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -6,8 +6,8 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff; + ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc; + ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little); + ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little); - ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little); - ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little); - ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little); + ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,10 +210,11 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - writeInt(out[0..], @truncate(u32, uu0), Endian.Little); - writeInt(out[4..], @truncate(u32, uu1), Endian.Little); - writeInt(out[8..], @truncate(u32, uu2), Endian.Little); - writeInt(out[12..], @truncate(u32, uu3), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); + writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); + writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); + writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index 1cb0b17434..d5aab8f33f 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -109,7 +109,8 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 7e9749364b..0476a3a25e 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } @@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); } } diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig index 881370e686..e686e1337c 100644 --- a/std/crypto/sha3.zig +++ b/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = []const u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); } comptime var x: usize = 0; @@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void { } for (s) |r, i| { - mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); } } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index 281813b457..daccb56808 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readInt(s[0..4], u32, Endian.Little); - t[1] = readInt(s[4..7], u32, Endian.Little) << 6; - t[2] = readInt(s[7..10], u32, Endian.Little) << 5; - t[3] = readInt(s[10..13], u32, Endian.Little) << 3; - t[4] = readInt(s[13..16], u32, Endian.Little) << 2; - t[5] = readInt(s[16..20], u32, Endian.Little); - t[6] = readInt(s[20..23], u32, Endian.Little) << 7; - t[7] = readInt(s[23..26], u32, Endian.Little) << 5; - t[8] = readInt(s[26..29], u32, Endian.Little) << 4; - t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2; + t[0] = readIntSliceLittle(u32, s[0..4]); + t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6; + t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5; + t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3; + t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2; + t[5] = readIntSliceLittle(u32, s[16..20]); + t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7; + t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5; + t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4; + t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,14 +544,15 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little); - writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); - writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); - writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); - writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); - writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); - writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); - writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/std/debug/index.zig b/std/debug/index.zig index 4a96e9d259..3967e5a8be 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -523,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void { const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo; - const signature = try modi.stream.readIntLe(u32); + const signature = try modi.stream.readIntLittle(u32); if (signature != 4) return error.InvalidDebugInfo; @@ -757,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { 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.readIntLe(u32); - const signature = try pdb_stream.stream.readIntLe(u32); - const age = try pdb_stream.stream.readIntLe(u32); + 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) @@ -767,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { // We validated the executable and pdb match. const string_table_index = str_tab_index: { - const name_bytes_len = try pdb_stream.stream.readIntLe(u32); + 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); @@ -797,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { }; const bucket_list = try allocator.alloc(Bucket, present.len); for (present) |_| { - const name_offset = try pdb_stream.stream.readIntLe(u32); - const name_index = try pdb_stream.stream.readIntLe(u32); + 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; @@ -859,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { 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.readIntLe(u32)); + const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32)); if (ver != pdb.SectionContrSubstreamVersion.Ver60) return error.InvalidDebugInfo; sect_cont_offset += @sizeOf(u32); @@ -879,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { } fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { - const num_words = try stream.readIntLe(u32); + 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.readIntLe(u32); + const word = try stream.readIntLittle(u32); var bit_i: u5 = 0; while (true) : (bit_i += 1) { if (word & (u32(1) << bit_i) != 0) { @@ -1200,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readInt(self.payload, u64, builtin.Endian.Little); + return mem.readIntSliceLittle(u64, self.payload); } }; @@ -1381,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize } fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); + const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } @@ -1395,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo } fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32)); + 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.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable; + 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 { @@ -1408,7 +1408,7 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) } fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue { - const block_len = try in_stream.readIntLe(T); + const block_len = try in_stream.readIntLittle(T); return parseFormValueRefLen(allocator, in_stream, block_len); } @@ -1450,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }, DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) }, + 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) }, @@ -1747,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr continue; } - const version = try di.dwarf_in_stream.readInt(di.endian, u16); + 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(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + 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(); @@ -1820,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(di.endian, usize); + const addr = try di.dwarf_in_stream.readInt(usize, di.endian); prog.address = addr; }, DW.LNE_define_file => { @@ -1882,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(di.endian, u16); + const arg = try di.dwarf_in_stream.readInt(u16, di.endian); prog.address += arg; }, DW.LNS_set_prologue_end => {}, @@ -1914,10 +1914,10 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { 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(di.endian, u16); + 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(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + 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; @@ -1978,8 +1978,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { 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.readIntLe(usize); - const end_addr = try di.dwarf_in_stream.readIntLe(usize); + 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; } @@ -2001,7 +2001,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { } fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { - const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian); + // TODO https://github.com/ziglang/zig/issues/863 + const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian); ptr.* += @sizeOf(T); return result; } @@ -2017,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 { } fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { - const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]); + // 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.readIntLE(u64, ptr.*[0..8]); + const result = mem.readIntSliceLittle(u64, ptr.*[0..8]); ptr.* += 8; return result; } else { @@ -2084,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 { } fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { - const first_32_bits = try in_stream.readIntLe(u32); + const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { - return in_stream.readIntLe(u64); + return in_stream.readIntLittle(u64); } else { if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; return u64(first_32_bits); diff --git a/std/elf.zig b/std/elf.zig index cf7c29b1e5..6a564c3283 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -412,7 +412,7 @@ pub const Elf = struct { // skip over padding try seekable_stream.seekForward(9); - elf.file_type = switch (try in.readInt(elf.endian, u16)) { + elf.file_type = switch (try in.readInt(u16, elf.endian)) { 1 => FileType.Relocatable, 2 => FileType.Executable, 3 => FileType.Shared, @@ -420,7 +420,7 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.arch = switch (try in.readInt(elf.endian, u16)) { + elf.arch = switch (try in.readInt(u16, elf.endian)) { 0x02 => Arch.Sparc, 0x03 => Arch.x86, 0x08 => Arch.Mips, @@ -433,32 +433,32 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - const elf_version = try in.readInt(elf.endian, u32); + const elf_version = try in.readInt(u32, elf.endian); if (elf_version != 1) return error.InvalidFormat; if (elf.is_64) { - elf.entry_addr = try in.readInt(elf.endian, u64); - elf.program_header_offset = try in.readInt(elf.endian, u64); - elf.section_header_offset = try in.readInt(elf.endian, u64); + elf.entry_addr = try in.readInt(u64, elf.endian); + elf.program_header_offset = try in.readInt(u64, elf.endian); + elf.section_header_offset = try in.readInt(u64, elf.endian); } else { - elf.entry_addr = u64(try in.readInt(elf.endian, u32)); - elf.program_header_offset = u64(try in.readInt(elf.endian, u32)); - elf.section_header_offset = u64(try in.readInt(elf.endian, u32)); + elf.entry_addr = u64(try in.readInt(u32, elf.endian)); + elf.program_header_offset = u64(try in.readInt(u32, elf.endian)); + elf.section_header_offset = u64(try in.readInt(u32, elf.endian)); } // skip over flags try seekable_stream.seekForward(4); - const header_size = try in.readInt(elf.endian, u16); + const header_size = try in.readInt(u16, elf.endian); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { return error.InvalidFormat; } - const ph_entry_size = try in.readInt(elf.endian, u16); - const ph_entry_count = try in.readInt(elf.endian, u16); - const sh_entry_size = try in.readInt(elf.endian, u16); - const sh_entry_count = try in.readInt(elf.endian, u16); - elf.string_section_index = u64(try in.readInt(elf.endian, u16)); + const ph_entry_size = try in.readInt(u16, elf.endian); + const ph_entry_count = try in.readInt(u16, elf.endian); + const sh_entry_size = try in.readInt(u16, elf.endian); + const sh_entry_count = try in.readInt(u16, elf.endian); + elf.string_section_index = u64(try in.readInt(u16, elf.endian)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -481,32 +481,32 @@ pub const Elf = struct { if (sh_entry_size != 64) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = try in.readInt(elf.endian, u64); - elf_section.addr = try in.readInt(elf.endian, u64); - elf_section.offset = try in.readInt(elf.endian, u64); - elf_section.size = try in.readInt(elf.endian, u64); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = try in.readInt(elf.endian, u64); - elf_section.ent_size = try in.readInt(elf.endian, u64); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = try in.readInt(u64, elf.endian); + elf_section.addr = try in.readInt(u64, elf.endian); + elf_section.offset = try in.readInt(u64, elf.endian); + elf_section.size = try in.readInt(u64, elf.endian); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = try in.readInt(u64, elf.endian); + elf_section.ent_size = try in.readInt(u64, elf.endian); } } else { if (sh_entry_size != 40) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = u64(try in.readInt(elf.endian, u32)); - elf_section.addr = u64(try in.readInt(elf.endian, u32)); - elf_section.offset = u64(try in.readInt(elf.endian, u32)); - elf_section.size = u64(try in.readInt(elf.endian, u32)); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = u64(try in.readInt(elf.endian, u32)); - elf_section.ent_size = u64(try in.readInt(elf.endian, u32)); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = u64(try in.readInt(u32, elf.endian)); + elf_section.addr = u64(try in.readInt(u32, elf.endian)); + elf_section.offset = u64(try in.readInt(u32, elf.endian)); + elf_section.size = u64(try in.readInt(u32, elf.endian)); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = u64(try in.readInt(u32, elf.endian)); + elf_section.ent_size = u64(try in.readInt(u32, elf.endian)); } } diff --git a/std/event/io.zig b/std/event/io.zig index bb377a3b68..b11550f7aa 100644 --- a/std/event/io.zig +++ b/std/event/io.zig @@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type { if (amt_read < buf.len) return error.EndOfStream; } - pub async fn readIntLe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Little, T) catch unreachable); + pub async fn readIntLittle(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readIntLittle(T, &bytes); } pub async fn readIntBe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Big, T) catch unreachable); - } - - pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try await (async self.readNoEof(bytes[0..]) catch unreachable); - return mem.readInt(bytes, T, endian); + return mem.readIntBig(T, &bytes); + } + + pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readInt(T, &bytes, endian); } pub async fn readStruct(self: *Self, comptime T: type) !T { diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index 0fe958c38b..ee26950272 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) pub fn init(key: []const u8) Self { debug.assert(key.len >= 16); - const k0 = mem.readInt(key[0..8], u64, Endian.Little); - const k1 = mem.readInt(key[8..16], u64, Endian.Little); + const k0 = mem.readIntSliceLittle(u64, key[0..8]); + const k1 = mem.readIntSliceLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) fn round(d: *Self, b: []const u8) void { debug.assert(b.len == 8); - const m = mem.readInt(b[0..], u64, Endian.Little); + const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; comptime var i: usize = 0; @@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; test "siphash64-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][8]u8{ "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc @@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u64, Endian.Little); + const expected = mem.readIntLittle(u64, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } test "siphash128-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][16]u8{ "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", @@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u128, Endian.Little); + const expected = mem.readIntLittle(u128, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/heap.zig b/std/heap.zig index 5c31d412cf..46b247fa7e 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -66,7 +66,7 @@ pub const DirectAllocator = struct { } } - fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { + fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { diff --git a/std/io.zig b/std/io.zig index bdca2b03e8..4442191717 100644 --- a/std/io.zig +++ b/std/io.zig @@ -152,35 +152,42 @@ pub fn InStream(comptime ReadError: type) type { } /// Reads a native-endian integer - pub fn readIntNe(self: *Self, comptime T: type) !T { - return self.readInt(builtin.endian, T); - } - - pub fn readIntLe(self: *Self, comptime T: type) !T { + pub fn readIntNative(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntLE(T, bytes); + return mem.readIntSliceNative(T, bytes); } - pub fn readIntBe(self: *Self, comptime T: type) !T { + /// Reads a foreign-endian integer + pub fn readIntForeign(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntBE(T, bytes); + return mem.readIntSliceForeign(T, bytes); } - pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { + pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, endian); + return mem.readIntSliceLittle(T, bytes); } - pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T { + pub fn readIntBig(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSliceBig(T, bytes); + } + + pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); + } + + pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { assert(size <= @sizeOf(T)); - assert(size <= 8); - var input_buf: [8]u8 = undefined; - const input_slice = input_buf[0..size]; - try self.readNoEof(input_slice); - return mem.readInt(input_slice, T, endian); + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { @@ -229,25 +236,34 @@ pub fn OutStream(comptime WriteError: type) type { } /// Write a native-endian integer. - pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void { - return self.writeInt(builtin.endian, T, value); - } - - pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void { + pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntLE(T, &bytes, value); + mem.writeIntNative(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void { + /// Write a foreign-endian integer. + pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntBE(T, &bytes, value); + mem.writeIntForeign(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void { + pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeInt(bytes[0..], value, endian); + mem.writeIntLittle(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeIntBig(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeInt(T, &bytes, value, endian); return self.writeFn(self, bytes); } }; diff --git a/std/mem.zig b/std/mem.zig index 9914a08e65..97dc46a80f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -407,186 +407,250 @@ test "mem.indexOf" { assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } -/// Reads an integer from memory with size equal to bytes.len. -/// T specifies the return type, which must be large enough to store -/// the result. -/// See also ::readIntBE or ::readIntLE. -pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T { - if (T.bit_count == 8) { - return bytes[0]; - } - var result: T = 0; - switch (endian) { - builtin.Endian.Big => { - for (bytes) |b| { - result = (result << 8) | b; - } - }, - builtin.Endian.Little => { - const ShiftType = math.Log2Int(T); - for (bytes) |b, index| { - result = result | (T(b) << @intCast(ShiftType, index * 8)); - } - }, - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @ptrCast(*align(1) const T, bytes).*; } -/// Reads a big-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntBE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes)); - } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result = (result << 8) | T(bytes[i]); - } - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @bswap(T, @ptrCast(*align(1) const T, bytes).*); } -/// Reads a little-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntLE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes)); - } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result |= T(bytes[i]) << i * 8; - } - } - return result; +pub const readIntLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntNative, + builtin.Endian.Big => readIntForeign, +}; + +pub const readIntBig = switch (builtin.endian) { + builtin.Endian.Little => readIntForeign, + builtin.Endian.Big => readIntNative, +}; + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -test "readIntBE/LE" { - assert(readIntBE(u0, []u8{}) == 0x0); - assert(readIntLE(u0, []u8{}) == 0x0); - - assert(readIntBE(u8, []u8{0x32}) == 0x32); - assert(readIntLE(u8, []u8{0x12}) == 0x12); - - assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234); - assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412); - - assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - - assert(readIntBE(i8, []u8{0xff}) == -1); - assert(readIntLE(i8, []u8{0xfe}) == -2); - - assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3); - assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4); +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes -/// to fill the entire buffer provided. -/// value must be an integer. -pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void { - const uint = @IntType(false, @typeOf(value).bit_count); +pub const readIntSliceLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceNative, + builtin.Endian.Big => readIntSliceForeign, +}; + +pub const readIntSliceBig = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceForeign, + builtin.Endian.Big => readIntSliceNative, +}; + +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { + if (endian == builtin.endian) { + return readIntNative(T, bytes); + } else { + return readIntForeign(T, bytes); + } +} + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); +} + +test "readIntBig and readIntLittle" { + assert(readIntSliceBig(u0, []u8{}) == 0x0); + assert(readIntSliceLittle(u0, []u8{}) == 0x0); + + assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); + assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); + + assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); + + assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + + assert(readIntSliceBig(i8, []u8{0xff}) == -1); + assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); + + assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, and +/// accepts any integer bit width. +/// This function stores in native endian, which means it is implemented as a simple +/// memory store. +pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = value; +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +/// This function stores in foreign endian, which means it does a @bswap first. +pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = @bswap(T, value); +} + +pub const writeIntLittle = switch (builtin.endian) { + builtin.Endian.Little => writeIntNative, + builtin.Endian.Big => writeIntForeign, +}; + +pub const writeIntBig = switch (builtin.endian) { + builtin.Endian.Little => writeIntForeign, + builtin.Endian.Big => writeIntNative, +}; + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + if (endian == builtin.endian) { + return writeIntNative(T, buffer, value); + } else { + return writeIntForeign(T, buffer, value); + } +} + +/// Writes a twos-complement little-endian integer to memory. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer after writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntLittle +/// instead. +pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); var bits = @truncate(uint, value); - switch (endian) { - builtin.Endian.Big => { - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - }, - builtin.Endian.Little => { - for (buf) |*b| { - b.* = @truncate(u8, bits); - bits >>= 8; - } - }, - } - assert(bits == 0); -} - -pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - assert(bits == 0); -} - -pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - for (buf) |*b| { + for (buffer) |*b| { b.* = @truncate(u8, bits); bits >>= 8; } - assert(bits == 0); } -test "writeIntBE/LE" { +/// Writes a twos-complement big-endian integer to memory. +/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer before writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntBig instead. +pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); + var bits = @truncate(uint, value); + var index: usize = buffer.len; + while (index != 0) { + index -= 1; + buffer[index] = @truncate(u8, bits); + bits >>= 8; + } +} + +pub const writeIntSliceNative = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceLittle, + builtin.Endian.Big => writeIntSliceBig, +}; + +pub const writeIntSliceForeign = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceBig, + builtin.Endian.Big => writeIntSliceLittle, +}; + +/// Writes a twos-complement integer to memory, with the specified endianness. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Any extra bytes in buffer not part of the integer are set to zero, with +/// respect to endianness. To avoid the branch to check for extra buffer bytes, +/// use writeInt instead. +pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + switch (endian) { + builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value), + builtin.Endian.Big => return writeIntSliceBig(T, buffer, value), + } +} + +test "writeIntBig and writeIntLittle" { var buf0: [0]u8 = undefined; var buf1: [1]u8 = undefined; var buf2: [2]u8 = undefined; var buf9: [9]u8 = undefined; - writeIntBE(u0, &buf0, 0x0); + writeIntBig(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntLE(u0, &buf0, 0x0); + writeIntLittle(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntBE(u8, &buf1, 0x12); + writeIntBig(u8, &buf1, 0x12); assert(eql_slice_u8(buf1[0..], []u8{0x12})); - writeIntLE(u8, &buf1, 0x34); + writeIntLittle(u8, &buf1, 0x34); assert(eql_slice_u8(buf1[0..], []u8{0x34})); - writeIntBE(u16, &buf2, 0x1234); + writeIntBig(u16, &buf2, 0x1234); assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); - writeIntLE(u16, &buf2, 0x5678); + writeIntLittle(u16, &buf2, 0x5678); assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); - writeIntBE(u72, &buf9, 0x123456789abcdef024); + writeIntBig(u72, &buf9, 0x123456789abcdef024); assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); - writeIntLE(u72, &buf9, 0xfedcba9876543210ec); + writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); - writeIntBE(i8, &buf1, -1); + writeIntBig(i8, &buf1, -1); assert(eql_slice_u8(buf1[0..], []u8{0xff})); - writeIntLE(i8, &buf1, -2); + writeIntLittle(i8, &buf1, -2); assert(eql_slice_u8(buf1[0..], []u8{0xfe})); - writeIntBE(i16, &buf2, -3); + writeIntBig(i16, &buf2, -3); assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); - writeIntLE(i16, &buf2, -4); + writeIntLittle(i16, &buf2, -4); assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } @@ -735,12 +799,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); - assert(readIntBE(u32, bytes) == 0x12345678); - assert(readIntBE(i32, bytes) == 0x12345678); - assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); - assert(readIntLE(u32, bytes) == 0x78563412); - assert(readIntLE(i32, bytes) == 0x78563412); + assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + assert(readIntBig(u32, &bytes) == 0x12345678); + assert(readIntBig(i32, &bytes) == 0x12345678); + assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + assert(readIntLittle(u32, &bytes) == 0x78563412); + assert(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -749,7 +813,7 @@ fn testReadIntImpl() void { 0x12, 0x34, }; - const answer = readInt(buf, u64, builtin.Endian.Big); + const answer = readInt(u32, &buf, builtin.Endian.Big); assert(answer == 0x00001234); } { @@ -759,7 +823,7 @@ fn testReadIntImpl() void { 0x00, 0x00, }; - const answer = readInt(buf, u64, builtin.Endian.Little); + const answer = readInt(u32, &buf, builtin.Endian.Little); assert(answer == 0x00003412); } { @@ -767,21 +831,33 @@ fn testReadIntImpl() void { 0xff, 0xfe, }; - assert(readIntBE(u16, bytes) == 0xfffe); - assert(readIntBE(i16, bytes) == -0x0002); - assert(readIntLE(u16, bytes) == 0xfeff); - assert(readIntLE(i16, bytes) == -0x0101); + assert(readIntBig(u16, &bytes) == 0xfffe); + assert(readIntBig(i16, &bytes) == -0x0002); + assert(readIntLittle(u16, &bytes) == 0xfeff); + assert(readIntLittle(i16, &bytes) == -0x0101); } } -test "testWriteInt" { +test "std.mem.writeIntSlice" { testWriteIntImpl(); comptime testWriteIntImpl(); } fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; - writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big); + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -793,7 +869,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little); + writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -805,7 +881,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); + writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -817,7 +893,7 @@ fn testWriteIntImpl() void { 0x78, })); - writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); + writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -829,7 +905,7 @@ fn testWriteIntImpl() void { 0x00, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -841,7 +917,7 @@ fn testWriteIntImpl() void { 0x34, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x34, 0x12, @@ -939,29 +1015,52 @@ test "std.mem.rotate" { })); } -// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by -// endian-casting the pointer and then dereferencing - -pub fn endianSwapIfLe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Little, T, x); +/// Converts a little-endian integer to host endianness. +pub fn littleToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; } -pub fn endianSwapIfBe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Big, T, x); +/// Converts a big-endian integer to host endianness. +pub fn bigToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } -pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T { - return if (builtin.endian == endian) endianSwap(T, x) else x; +/// Converts an integer from specified endianness to host endianness. +pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { + return switch (endianness_of_x) { + builtin.Endian.Little => littleToNative(T, x), + builtin.Endian.Big => bigToNative(T, x), + }; } -pub fn endianSwap(comptime T: type, x: T) T { - var buf: [@sizeOf(T)]u8 = undefined; - mem.writeInt(buf[0..], x, builtin.Endian.Little); - return mem.readInt(buf, T, builtin.Endian.Big); +/// Converts an integer which has host endianness to the desired endianness. +pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { + return switch (desired_endianness) { + builtin.Endian.Little => nativeToLittle(T, x), + builtin.Endian.Big => nativeToBig(T, x), + }; } -test "std.mem.endianSwap" { - assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE); +/// Converts an integer which has host endianness to little endian. +pub fn nativeToLittle(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; +} + +/// Converts an integer which has host endianness to big endian. +pub fn nativeToBig(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } fn AsBytesReturnType(comptime P: type) type { diff --git a/std/net.zig b/std/net.zig index 006a9d4ac5..968c1f019f 100644 --- a/std/net.zig +++ b/std/net.zig @@ -23,7 +23,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{ .family = posix.AF_INET, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .addr = ip4, .zero = []u8{0} ** 8, }, @@ -37,7 +37,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{ .family = posix.AF_INET6, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .flowinfo = 0, .addr = ip6.addr, .scope_id = ip6.scope_id, @@ -47,7 +47,7 @@ pub const Address = struct { } pub fn port(self: Address) u16 { - return std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + return mem.bigToNative(u16, self.os_addr.in.port); } pub fn initPosix(addr: posix.sockaddr) Address { @@ -57,12 +57,12 @@ pub const Address = struct { pub fn format(self: *const Address, out_stream: var) !void { switch (self.os_addr.in.family) { posix.AF_INET => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port); const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]); try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port); }, posix.AF_INET6 => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port); try out_stream.print("[TODO render ip6 address]:{}", native_endian_port); }, else => try out_stream.write("(unrecognized address family)"), @@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr { } test "std.net.parseIp4" { - assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001)); + assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001)); testParseIp4Fail("256.0.0.1", error.Overflow); testParseIp4Fail("x.0.0.1", error.InvalidCharacter); diff --git a/std/os/child_process.zig b/std/os/child_process.zig index c8865bfacd..0aa896ff1b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -807,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { const stream = &os.File.openHandle(fd).outStream().stream; - stream.writeIntNe(ErrInt, value) catch return error.SystemResources; + stream.writeIntNative(ErrInt, value) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { const stream = &os.File.openHandle(fd).inStream().stream; - return stream.readIntNe(ErrInt) catch return error.SystemResources; + return stream.readIntNative(ErrInt) catch return error.SystemResources; } diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index 20a6710596..509075386f 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -98,12 +98,12 @@ pub nakedcc fn restore_rt() void { } pub const msghdr = extern struct { - msg_name: &u8, + msg_name: *u8, msg_namelen: socklen_t, - msg_iov: &iovec, + msg_iov: *iovec, msg_iovlen: i32, __pad1: i32, - msg_control: &u8, + msg_control: *u8, msg_controllen: socklen_t, __pad2: socklen_t, msg_flags: i32, diff --git a/std/pdb.zig b/std/pdb.zig index 2c5df3e597..0cfc6a6cda 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -508,11 +508,11 @@ const Msf = struct { allocator, ); - const stream_count = try self.directory.stream.readIntLe(u32); + const stream_count = try self.directory.stream.readIntLittle(u32); const stream_sizes = try allocator.alloc(u32, stream_count); for (stream_sizes) |*s| { - const size = try self.directory.stream.readIntLe(u32); + const size = try self.directory.stream.readIntLittle(u32); s.* = blockCountFromSize(size, superblock.BlockSize); } @@ -603,7 +603,7 @@ const MsfStream = struct { var i: u32 = 0; while (i < block_count) : (i += 1) { - stream.blocks[i] = try in.readIntLe(u32); + stream.blocks[i] = try in.readIntLittle(u32); } return stream; diff --git a/std/rand/index.zig b/std/rand/index.zig index 97101bc3b7..c335063e64 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.os.getRandomBytes(buf[0..]); -// const seed = mem.readIntLE(u64, buf[0..8]); +// const seed = mem.readIntSliceLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // @@ -52,7 +52,7 @@ pub const Random = struct { // 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.readIntLE(ByteAlignedT, rand_bytes); + const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes); const unsigned_result = @truncate(UnsignedT, byte_aligned_result); return @bitCast(T, unsigned_result); } @@ -69,6 +69,7 @@ pub const Random = struct { 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. @@ -123,6 +124,7 @@ pub const Random = struct { } 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. @@ -151,6 +153,7 @@ pub const Random = struct { 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. @@ -185,6 +188,7 @@ pub const Random = struct { 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. diff --git a/std/unicode.zig b/std/unicode.zig index fcb748401f..2e542bcb19 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -249,12 +249,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u32 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c0: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c0 & ~u32(0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c1: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -510,46 +510,46 @@ test "utf16leToUtf8" { const utf16le_as_bytes = @sliceToBytes(utf16le[0..]); { - mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "Aa")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { // the values just outside the surrogate half range - mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { // smallest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { // largest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } @@ -583,7 +583,7 @@ pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { while (it.nextCodepoint()) |codepoint| { if (end_index == utf16le_as_bytes.len) return (end_index / 2) + 1; // TODO surrogate pairs - mem.writeInt(utf16le_as_bytes[end_index..], @intCast(u16, codepoint), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[end_index..], @intCast(u16, codepoint)); end_index += 2; } return end_index / 2; diff --git a/test/behavior.zig b/test/behavior.zig index 1d031343d6..499c20ee20 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -8,6 +8,7 @@ comptime { _ = @import("cases/atomics.zig"); _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); + _ = @import("cases/bswap.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); @@ -64,6 +65,7 @@ comptime { _ = @import("cases/switch_prong_implicit_cast.zig"); _ = @import("cases/syntax.zig"); _ = @import("cases/this.zig"); + _ = @import("cases/truncate.zig"); _ = @import("cases/try.zig"); _ = @import("cases/type_info.zig"); _ = @import("cases/undefined.zig"); diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig new file mode 100644 index 0000000000..57993077e1 --- /dev/null +++ b/test/cases/bswap.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "@bswap" { + comptime testByteSwap(); + testByteSwap(); +} + +fn testByteSwap() void { + assert(@bswap(u0, 0) == 0); + assert(@bswap(u8, 0x12) == 0x12); + assert(@bswap(u16, 0x1234) == 0x3412); + assert(@bswap(u24, 0x123456) == 0x563412); + assert(@bswap(u32, 0x12345678) == 0x78563412); + assert(@bswap(u40, 0x123456789a) == 0x9a78563412); + assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + + assert(@bswap(i0, 0) == 0); + assert(@bswap(i8, -50) == -50); + assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); +} diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig new file mode 100644 index 0000000000..02b5085ccd --- /dev/null +++ b/test/cases/truncate.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "truncate u0 to larger integer allowed and has comptime known result" { + var x: u0 = 0; + const y = @truncate(u8, x); + comptime assert(y == 0); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index be839f0550..ee3741ee6b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,18 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "reading past end of pointer casted array", + \\comptime { + \\ const array = "aoeu"; + \\ const slice = array[2..]; + \\ const int_ptr = @ptrCast(*const u24, slice.ptr); + \\ const deref = int_ptr.*; + \\} + , + ".tmp_source.zig:5:26: error: attempt to read 3 bytes from [4]u8 at index 2 which is 2 bytes", + ); + cases.add( "error note for function parameter incompatibility", \\fn do_the_thing(func: fn (arg: i32) void) void {} From d770333827549e5dcbb727c7f434eaac9dd433d2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 Dec 2018 22:28:15 -0500 Subject: [PATCH 020/218] freebsd: fix os_self_exe_path function and update std lib --- src/os.cpp | 2 +- std/os/freebsd/index.zig | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/os.cpp b/src/os.cpp index eba95b9f2f..2f0379c09b 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1456,7 +1456,7 @@ Error os_self_exe_path(Buf *out_path) { if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) { return ErrorUnexpected; } - buf_resize(out_path, cb); + buf_resize(out_path, cb - 1); return ErrorNone; #endif return ErrorFileNotFound; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 75389fc403..9fbeaf1dc1 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -9,6 +9,7 @@ pub use @import("errno.zig"); const std = @import("../../index.zig"); const c = std.c; +const maxInt = std.math.maxInt; pub const Kevent = c.Kevent; pub const PATH_MAX = 1024; @@ -22,7 +23,7 @@ pub const PROT_READ = 1; pub const PROT_WRITE = 2; pub const PROT_EXEC = 4; -pub const MAP_FAILED = @maxValue(usize); +pub const MAP_FAILED = maxInt(usize); pub const MAP_SHARED = 0x0001; pub const MAP_PRIVATE = 0x0002; pub const MAP_FIXED = 0x0010; @@ -700,7 +701,7 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{@maxValue(usize)}; +const all_mask = []usize{maxInt(usize)}; const app_mask = []usize{0xfffffffc7fffffff}; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. @@ -711,7 +712,7 @@ pub const Sigaction = struct { flags: u32, }; -pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize)); +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; From 7417f2e4b3a9c21249bac38688ef453c6b86acfa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 00:33:13 -0500 Subject: [PATCH 021/218] freebsd: fix issues with syscalls --- std/os/freebsd/index.zig | 133 ++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 9fbeaf1dc1..34a3414a48 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -158,7 +158,6 @@ pub const SOCK_SEQPACKET = 5; pub const SOCK_CLOEXEC = 0x10000000; pub const SOCK_NONBLOCK = 0x20000000; -// TODO: From here pub const PROTO_ip = 0o000; pub const PROTO_icmp = 0o001; pub const PROTO_igmp = 0o002; @@ -540,7 +539,7 @@ pub fn getErrno(r: usize) usize { } pub fn dup2(old: i32, new: i32) usize { - return arch.syscall2(SYS_dup2, @intCast(usize, old), @intCast(usize, new)); + return arch.syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); } pub fn chdir(path: [*]const u8) usize { @@ -560,12 +559,12 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { - return arch.syscall3(SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count); + return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); } pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return arch.syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { @@ -577,7 +576,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize { } pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { - return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); + return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); } pub fn munmap(address: usize, length: usize) usize { @@ -585,7 +584,7 @@ pub fn munmap(address: usize, length: usize) usize { } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return arch.syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn rmdir(path: [*]const u8) usize { @@ -597,11 +596,11 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize { - return arch.syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return arch.syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn pipe(fd: *[2]i32) usize { @@ -613,15 +612,15 @@ pub fn pipe2(fd: *[2]i32, flags: usize) usize { } pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return arch.syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return arch.syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn rename(old: [*]const u8, new: [*]const u8) usize { @@ -637,15 +636,15 @@ pub fn create(path: [*]const u8, perm: usize) usize { } pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { - return arch.syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); + return arch.syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); } pub fn close(fd: i32) usize { - return arch.syscall1(SYS_close, @intCast(usize, fd)); + return arch.syscall1(SYS_close, @bitCast(usize, isize(fd))); } pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return arch.syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); + return arch.syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); } pub fn exit(status: i32) noreturn { @@ -654,11 +653,11 @@ pub fn exit(status: i32) noreturn { } pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { - return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags)); + return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); } pub fn kill(pid: i32, sig: i32) usize { - return arch.syscall2(SYS_kill, @bitCast(usize, @intCast(isize, pid)), @intCast(usize, sig)); + return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); } pub fn unlink(path: [*]const u8) usize { @@ -689,66 +688,65 @@ pub fn setregid(rgid: u32, egid: u32) usize { return arch.syscall2(SYS_setregid, rgid, egid); } -pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { - // TODO: Implement - return 0; -} - -pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { - // TODO: Implement - return 0; -} - -const NSIG = 65; -const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{maxInt(usize)}; -const app_mask = []usize{0xfffffffc7fffffff}; - -/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. -pub const Sigaction = struct { - // TODO: Adjust to use freebsd struct layout - handler: extern fn (i32) void, - mask: sigset_t, - flags: u32, -}; +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); -pub const empty_sigset = []usize{0} ** sigset_t.len; + +/// 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 { - // TODO implement, see linux equivalent for what we want to try and do - return 0; -} - -fn blockAllSignals(set: *sigset_t) void { - // TODO implement -} - -fn blockAppSignals(set: *sigset_t) void { - // TODO implement -} - -fn restoreSignals(set: *sigset_t) void { - // TODO implement -} - -pub fn sigaddset(set: *sigset_t, sig: u6) void { - const s = sig - 1; - (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1)); -} - -pub fn sigismember(set: *const sigset_t, sig: u6) bool { - const s = sig - 1; - return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0; + // TODO have a chat with the freebsd folks and make sure there's no bug in + // their libc. musl-libc blocks signals in between these calls because + // if a signal handler runs and forks between the gettid and sending the + // signal, the parent will get 2 signals, one from itself and one from the child + // if the protection does not belong here, then it belongs in abort(), + // like it does in freebsd's libc. + var id: usize = undefined; + const rc = arch.syscall1(SYS_thr_self, @ptrToInt(&id)); + if (getErrno(rc) != 0) return rc; + return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig))); } pub const Stat = arch.Stat; pub const timespec = arch.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); + return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); } pub const iovec = extern struct { @@ -761,10 +759,12 @@ pub const iovec_const = extern struct { 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, @@ -776,18 +776,23 @@ pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, 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. From 6395cf8d6b2cf585214a284039c16d6dc5ef5de3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 06:07:39 -0500 Subject: [PATCH 022/218] fix mistakes introduced in b883bc8 --- doc/langref.html.in | 2 +- std/io.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f820a05b69..c1a6160e04 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5313,7 +5313,7 @@ comptime { {#header_close#} {#header_open|@bswap#} -

{#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+
{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, diff --git a/std/io.zig b/std/io.zig index 4442191717..8d33dfc5ea 100644 --- a/std/io.zig +++ b/std/io.zig @@ -186,7 +186,7 @@ pub fn InStream(comptime ReadError: type) type { pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { assert(size <= @sizeOf(T)); var bytes: [@sizeOf(T)]u8 = undefined; - try self.readNoEof(bytes[0..]); + try self.readNoEof(bytes[0..size]); return mem.readIntSlice(T, bytes, endian); } From e98ba5fc4044cd84ab88b10cb8c88d765884462f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 06:38:14 -0500 Subject: [PATCH 023/218] add mem.readVarInt, fix InStream.readVarInt, fix stack traces fixes a regression from b883bc8 --- std/debug/index.zig | 2 +- std/io.zig | 11 ++++++----- std/mem.zig | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 3967e5a8be..73c6ea7b56 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1200,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readIntSliceLittle(u64, self.payload); + return mem.readVarInt(u64, self.payload, builtin.Endian.Little); } }; diff --git a/std/io.zig b/std/io.zig index 8d33dfc5ea..c40ededc00 100644 --- a/std/io.zig +++ b/std/io.zig @@ -183,11 +183,12 @@ pub fn InStream(comptime ReadError: type) type { return mem.readIntSlice(T, bytes, endian); } - pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { - assert(size <= @sizeOf(T)); - var bytes: [@sizeOf(T)]u8 = undefined; - try self.readNoEof(bytes[0..size]); - return mem.readIntSlice(T, bytes, endian); + pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType { + assert(size <= @sizeOf(ReturnType)); + var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined; + const bytes = bytes_buf[0..size]; + try self.readNoEof(bytes); + return mem.readVarInt(ReturnType, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { diff --git a/std/mem.zig b/std/mem.zig index 97dc46a80f..393033f22a 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -407,6 +407,27 @@ test "mem.indexOf" { assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } +/// Reads an integer from memory with size equal to bytes.len. +/// T specifies the return type, which must be large enough to store +/// the result. +pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType { + var result: ReturnType = 0; + switch (endian) { + builtin.Endian.Big => { + for (bytes) |b| { + result = (result << 8) | b; + } + }, + builtin.Endian.Little => { + const ShiftType = math.Log2Int(ReturnType); + for (bytes) |b, index| { + result = result | (ReturnType(b) << @intCast(ShiftType, index * 8)); + } + }, + } + return result; +} + /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. From fff6e471259071d9ad8466bcdb0ce42c9d7a90d4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 17:13:10 -0500 Subject: [PATCH 024/218] fixups --- std/buf_map.zig | 42 +++++++++++++++++++++++++++------------ std/os/index.zig | 51 ++++++++++++------------------------------------ 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/std/buf_map.zig b/std/buf_map.zig index a82d1b731a..6de0d20cdb 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -16,7 +16,7 @@ pub const BufMap = struct { return self; } - pub fn deinit(self: *const BufMap) void { + pub fn deinit(self: *BufMap) void { var it = self.hash_map.iterator(); while (true) { const entry = it.next() orelse break; @@ -27,16 +27,34 @@ pub const BufMap = struct { self.hash_map.deinit(); } - pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void { - self.delete(key); - const key_copy = try self.copy(key); - errdefer self.free(key_copy); - const value_copy = try self.copy(value); - errdefer self.free(value_copy); - _ = try self.hash_map.put(key_copy, value_copy); + /// Same as `set` but the key and value become owned by the BufMap rather + /// than being copied. + /// If `setMove` fails, the ownership of key and value does not transfer. + pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void { + const get_or_put = try self.hash_map.getOrPut(key); + if (get_or_put.found_existing) { + self.free(get_or_put.kv.key); + get_or_put.kv.key = key; + } + get_or_put.kv.value = value; } - pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 { + /// `key` and `value` are copied into the BufMap. + pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void { + const value_copy = try self.copy(value); + errdefer self.free(value_copy); + // Avoid copying key if it already exists + const get_or_put = try self.hash_map.getOrPut(key); + if (!get_or_put.found_existing) { + get_or_put.kv.key = self.copy(key) catch |err| { + _ = self.hash_map.remove(key); + return err; + }; + } + get_or_put.kv.value = value_copy; + } + + pub fn get(self: BufMap, key: []const u8) ?[]const u8 { const entry = self.hash_map.get(key) orelse return null; return entry.value; } @@ -47,7 +65,7 @@ pub const BufMap = struct { self.free(entry.value); } - pub fn count(self: *const BufMap) usize { + pub fn count(self: BufMap) usize { return self.hash_map.count(); } @@ -55,11 +73,11 @@ pub const BufMap = struct { return self.hash_map.iterator(); } - fn free(self: *const BufMap, value: []const u8) void { + fn free(self: BufMap, value: []const u8) void { self.hash_map.allocator.free(value); } - fn copy(self: *const BufMap, value: []const u8) ![]const u8 { + fn copy(self: BufMap, value: []const u8) ![]u8 { return mem.dupe(self.hash_map.allocator, u8, value); } }; diff --git a/std/os/index.zig b/std/os/index.zig index 779fa8f8c8..be82ad4716 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -705,54 +705,28 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); - var buf: [100]u8 = undefined; - var i: usize = 0; while (true) { if (ptr[i] == 0) return result; const key_start = i; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - - const key_slice = ptr[key_start..i]; - var key: []u8 = undefined; - var heap_key = false; - - key = std.unicode.utf16leToUtf8Alloc(fallocator, key_slice) catch undefined; - - if (key.len == 0) { - key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); - heap_key = true; - } + 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_slice = ptr[value_start..i]; - var value: []u8 = undefined; - var heap_value = false; - - value = std.unicode.utf16leToUtf8Alloc(fallocator, value_slice) catch undefined; - - if (value.len == 0) { - value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); - heap_value = true; - } + 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.set(key, value); - - if (heap_key) { - allocator.free(key); - } - if (heap_value) { - allocator.free(value); - } + try result.setMove(key, value); } } else { for (posix_environ_raw) |ptr| { @@ -795,9 +769,6 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { pub const GetEnvVarOwnedError = error{ OutOfMemory, EnvironmentVariableNotFound, - DanglingSurrogateHalf, - ExpectedSecondSurrogateHalf, - UnexpectedSecondSurrogateHalf, /// See https://github.com/ziglang/zig/issues/1774 InvalidUtf8, @@ -833,7 +804,12 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned continue; } - return try std.unicode.utf16leToUtf8Alloc(allocator, buf); + 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; @@ -846,7 +822,6 @@ test "os.getEnvVarOwned" { debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); } - /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; From 82bf1eb7a1ae54f0bb52fdb8fdcd89fdaab683f0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Dec 2018 20:21:23 -0500 Subject: [PATCH 025/218] docs: fix alphabetical sorting of builtin functions --- doc/langref.html.in | 187 +++++++++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 71 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index c1a6160e04..f41eb2dec1 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5169,6 +5169,34 @@ fn seq(c: u8) void { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@alignCast#} +
{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
+

+ {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#}, + {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#} + except with the alignment adjusted to the new value. +

+

A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added + to the generated code to make sure the pointer is aligned as promised.

+ + {#header_close#} + {#header_open|@alignOf#} +
{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}
+

+ This function returns the number of bytes that this type should be aligned to + for the current target to match the C ABI. When the child type of a pointer has + this alignment, the alignment can be omitted from the type. +

+
{#syntax#}const assert = @import("std").debug.assert;
+comptime {
+    assert(*u32 == *align(@alignOf(u32)) u32);
+}{#endsyntax#}
+

+ The result is a target-specific compile time constant. It is guaranteed to be + less than or equal to {#link|@sizeOf(T)|@sizeOf#}. +

+ {#see_also|Alignment#} + {#header_close#} {#header_open|@ArgType#}
{#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}

@@ -5241,6 +5269,7 @@ fn seq(c: u8) void { Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.

{#header_close#} + {#header_open|@bitOffsetOf#}
{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}

@@ -5253,52 +5282,6 @@ fn seq(c: u8) void {

{#see_also|@byteOffsetOf#} {#header_close#} - {#header_open|@breakpoint#} -
{#syntax#}@breakpoint(){#endsyntax#}
-

- This function inserts a platform-specific debug trap instruction which causes - debuggers to break there. -

-

- This function is only valid within function scope. -

- - {#header_close#} - {#header_open|@byteOffsetOf#} -
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}
-

- Returns the byte offset of a field relative to its containing struct. -

- {#see_also|@bitOffsetOf#} - {#header_close#} - {#header_open|@alignCast#} -
{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
-

- {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#}, - {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#} - except with the alignment adjusted to the new value. -

-

A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added - to the generated code to make sure the pointer is aligned as promised.

- - {#header_close#} - {#header_open|@alignOf#} -
{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}
-

- This function returns the number of bytes that this type should be aligned to - for the current target to match the C ABI. When the child type of a pointer has - this alignment, the alignment can be omitted from the type. -

-
{#syntax#}const assert = @import("std").debug.assert;
-comptime {
-    assert(*u32 == *align(@alignOf(u32)) u32);
-}{#endsyntax#}
-

- The result is a target-specific compile time constant. It is guaranteed to be - less than or equal to {#link|@sizeOf(T)|@sizeOf#}. -

- {#see_also|Alignment#} - {#header_close#} {#header_open|@boolToInt#}
{#syntax#}@boolToInt(value: bool) u1{#endsyntax#}
@@ -5312,6 +5295,18 @@ comptime {

{#header_close#} + {#header_open|@breakpoint#} +
{#syntax#}@breakpoint(){#endsyntax#}
+

+ This function inserts a platform-specific debug trap instruction which causes + debuggers to break there. +

+

+ This function is only valid within function scope. +

+ + {#header_close#} + {#header_open|@bswap#}
{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

@@ -5321,6 +5316,14 @@ comptime {

{#header_close#} + {#header_open|@byteOffsetOf#} +
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}
+

+ Returns the byte offset of a field relative to its containing struct. +

+ {#see_also|@bitOffsetOf#} + {#header_close#} + {#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}

@@ -5387,17 +5390,7 @@ comptime {

{#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#} {#header_close#} - {#header_open|@cUndef#} -
{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
-

- This function can only occur inside {#syntax#}@cImport{#endsyntax#}. -

-

- This appends #undef $name to the {#syntax#}@cImport{#endsyntax#} - temporary buffer. -

- {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} - {#header_close#} + {#header_open|@clz#}
{#syntax#}@clz(x: T) U{#endsyntax#}

@@ -5413,6 +5406,7 @@ comptime {

{#see_also|@ctz|@popCount#} {#header_close#} + {#header_open|@cmpxchgStrong#}
{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}

@@ -5468,6 +5462,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val

{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}

{#see_also|Compile Variables|cmpxchgStrong#} {#header_close#} + {#header_open|@compileError#}
{#syntax#}@compileError(comptime msg: []u8){#endsyntax#}

@@ -5480,6 +5475,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val and {#syntax#}comptime{#endsyntax#} functions.

{#header_close#} + {#header_open|@compileLog#}
{#syntax#}@compileLog(args: ...){#endsyntax#}

@@ -5534,6 +5530,7 @@ test "main" { } {#code_end#} {#header_close#} + {#header_open|@ctz#}

{#syntax#}@ctz(x: T) U{#endsyntax#}

@@ -5549,6 +5546,19 @@ test "main" {

{#see_also|@clz|@popCount#} {#header_close#} + + {#header_open|@cUndef#} +
{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
+

+ This function can only occur inside {#syntax#}@cImport{#endsyntax#}. +

+

+ This appends #undef $name to the {#syntax#}@cImport{#endsyntax#} + temporary buffer. +

+ {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} + {#header_close#} + {#header_open|@divExact#}
{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}

@@ -5615,14 +5625,6 @@ test "main" { {#see_also|@intToEnum#} {#header_close#} - {#header_open|@errSetCast#} -

{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
-

- Converts an error value from one error set to another error set. Attempting to convert an error - which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. -

- {#header_close#} - {#header_open|@errorName#}
{#syntax#}@errorName(err: anyerror) []const u8{#endsyntax#}

@@ -5665,6 +5667,14 @@ test "main" { {#see_also|@intToError#} {#header_close#} + {#header_open|@errSetCast#} +

{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
+

+ Converts an error value from one error set to another error set. Attempting to convert an error + which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. +

+ {#header_close#} + {#header_open|@export#}
{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}

@@ -5733,6 +5743,7 @@ test "main" { This function is only valid within function scope.

{#header_close#} + {#header_open|@handle#}
{#syntax#}@handle(){#endsyntax#}

@@ -5743,6 +5754,7 @@ test "main" { This function is only valid within an async function scope.

{#header_close#} + {#header_open|@import#}
{#syntax#}@import(comptime path: []u8) (namespace){#endsyntax#}

@@ -5763,6 +5775,7 @@ test "main" { {#see_also|Compile Variables|@embedFile#} {#header_close#} + {#header_open|@inlineCall#}

{#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}

@@ -5842,6 +5855,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } bit count for an integer type is {#syntax#}65535{#endsyntax#}.

{#header_close#} + {#header_open|@memberCount#}
{#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}

@@ -5868,6 +5882,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }

{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}

Returns the field type of a struct or union.

{#header_close#} + {#header_open|@memcpy#}
{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}

@@ -5886,6 +5901,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }

{#syntax#}const mem = @import("std").mem;
 mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
{#header_close#} + {#header_open|@memset#}
{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}

@@ -5903,6 +5919,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}

{#syntax#}const mem = @import("std").mem;
 mem.set(u8, dest, c);{#endsyntax#}
{#header_close#} + {#header_open|@mod#}
{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}

@@ -5916,6 +5933,7 @@ mem.set(u8, dest, c);{#endsyntax#}

For a function that returns an error code, see {#syntax#}@import("std").math.mod{#endsyntax#}.

{#see_also|@rem#} {#header_close#} + {#header_open|@mulWithOverflow#}
{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}

@@ -5924,6 +5942,7 @@ mem.set(u8, dest, c);{#endsyntax#} If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@newStackCall#}
{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}

@@ -5960,6 +5979,7 @@ fn targetFunction(x: i32) usize { } {#code_end#} {#header_close#} + {#header_open|@noInlineCall#}

{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}

@@ -5982,6 +6002,7 @@ fn add(a: i32, b: i32) i32 {

{#see_also|@inlineCall#} {#header_close#} + {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

@@ -6005,6 +6026,7 @@ test "call foo" { } {#code_end#} {#header_close#} + {#header_open|@panic#}

{#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}

@@ -6021,6 +6043,7 @@ test "call foo" { {#see_also|Root Source File#} {#header_close#} + {#header_open|@popCount#}

{#syntax#}@popCount(integer: var) var{#endsyntax#}

Counts the number of bits set in an integer.

@@ -6031,12 +6054,14 @@ test "call foo" {

{#see_also|@ctz|@clz#} {#header_close#} + {#header_open|@ptrCast#}
{#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}

Converts a pointer of one type to a pointer of another type.

{#header_close#} + {#header_open|@ptrToInt#}
{#syntax#}@ptrToInt(value: var) usize{#endsyntax#}

@@ -6051,6 +6076,7 @@ test "call foo" {

To convert the other way, use {#link|@intToPtr#}

{#header_close#} + {#header_open|@rem#}
{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}

@@ -6064,6 +6090,7 @@ test "call foo" {

For a function that returns an error code, see {#syntax#}@import("std").math.rem{#endsyntax#}.

{#see_also|@mod#} {#header_close#} + {#header_open|@returnAddress#}
{#syntax#}@returnAddress(){#endsyntax#}

@@ -6084,19 +6111,14 @@ test "call foo" { Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.

{#header_close#} + {#header_open|@setCold#}
{#syntax#}@setCold(is_cold: bool){#endsyntax#}

Tells the optimizer that a function is rarely called.

{#header_close#} - {#header_open|@setRuntimeSafety#} -
{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}
-

- Sets whether runtime safety checks are on for the scope that contains the function call. -

- {#header_close#} {#header_open|@setEvalBranchQuota#}
{#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}

@@ -6131,6 +6153,7 @@ test "foo" { {#see_also|comptime#} {#header_close#} + {#header_open|@setFloatMode#}

{#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}

@@ -6165,6 +6188,7 @@ pub const FloatMode = enum {

{#see_also|Floating Point Operations#} {#header_close#} + {#header_open|@setGlobalLinkage#}
{#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}

@@ -6172,6 +6196,15 @@ pub const FloatMode = enum {

{#see_also|Compile Variables#} {#header_close#} + + {#header_open|@setRuntimeSafety#} +
{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}
+

+ Sets whether runtime safety checks are on for the scope that contains the function call. +

+ + {#header_close#} + {#header_open|@shlExact#}
{#syntax#}@shlExact(value: T, shift_amt: Log2T) T{#endsyntax#}

@@ -6184,6 +6217,7 @@ pub const FloatMode = enum {

{#see_also|@shrExact|@shlWithOverflow#} {#header_close#} + {#header_open|@shlWithOverflow#}
{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}

@@ -6197,6 +6231,7 @@ pub const FloatMode = enum {

{#see_also|@shlExact|@shrExact#} {#header_close#} + {#header_open|@shrExact#}
{#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}

@@ -6238,6 +6273,7 @@ pub const FloatMode = enum { This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.

{#header_close#} + {#header_open|@subWithOverflow#}
{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}

@@ -6246,12 +6282,14 @@ pub const FloatMode = enum { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@tagName#}
{#syntax#}@tagName(value: var) []const u8{#endsyntax#}

Converts an enum value or union value to a slice of bytes representing the name.

{#header_close#} + {#header_open|@TagType#}
{#syntax#}@TagType(T: type) type{#endsyntax#}

@@ -6261,6 +6299,7 @@ pub const FloatMode = enum { For a union, returns the enum type that is used to store the tag value.

{#header_close#} + {#header_open|@This#}
{#syntax#}@This() type{#endsyntax#}

@@ -6296,6 +6335,7 @@ fn List(comptime T: type) type { #1047 for details.

{#header_close#} + {#header_open|@truncate#}
{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}

@@ -6320,6 +6360,7 @@ const b: u8 = @truncate(u8, a);

{#header_close#} + {#header_open|@typeId#}
{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}

@@ -6354,6 +6395,7 @@ pub const TypeId = enum { }; {#code_end#} {#header_close#} + {#header_open|@typeInfo#}

{#syntax#}@typeInfo(comptime T: type) @import("builtin").TypeInfo{#endsyntax#}

@@ -6536,6 +6578,7 @@ pub const TypeInfo = union(TypeId) { }; {#code_end#} {#header_close#} + {#header_open|@typeName#}

{#syntax#}@typeName(T: type) []u8{#endsyntax#}

@@ -6543,6 +6586,7 @@ pub const TypeInfo = union(TypeId) {

{#header_close#} + {#header_open|@typeOf#}
{#syntax#}@typeOf(expression) type{#endsyntax#}

@@ -6552,6 +6596,7 @@ pub const TypeInfo = union(TypeId) { {#header_close#} {#header_close#} + {#header_open|Build Mode#}

Zig has four build modes: From 624c74af6f61da55e2ba5dcb6b8605b6aec2cea2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 11:22:33 -0500 Subject: [PATCH 026/218] ci: install openssl on windows --- ci/azure/windows_install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure/windows_install b/ci/azure/windows_install index 952e9f78cb..760520e0b9 100755 --- a/ci/azure/windows_install +++ b/ci/azure/windows_install @@ -3,7 +3,7 @@ set -x set -e -pacman -S --needed --noconfirm wget p7zip python3-pip +pacman -S --needed --noconfirm wget p7zip python3-pip openssl pip install s3cmd wget -nv "https://ziglang.org/deps/llvm%2bclang-7.0.0-win64-msvc-release.tar.xz" tar xf llvm+clang-7.0.0-win64-msvc-release.tar.xz From 7533d1b14cb105f604cac3bd1e9dd99cab7a0c2b Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sun, 16 Dec 2018 11:14:53 -0500 Subject: [PATCH 027/218] mem foreign functions call the native ones this reduces the amount of implementation to change for #1835 --- std/mem.zig | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index 393033f22a..b9772acd6d 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -443,8 +443,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { - comptime assert(T.bit_count % 8 == 0); - return @bswap(T, @ptrCast(*align(1) const T, bytes).*); + return @bswap(T, readIntNative(T, bytes)); } pub const readIntLittle = switch (builtin.endian) { @@ -476,10 +475,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); - // TODO https://github.com/ziglang/zig/issues/863 - return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); + return @bswap(T, readIntSliceNative(T, bytes)); } pub const readIntSliceLittle = switch (builtin.endian) { @@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { /// the integer bit width must be divisible by 8. /// This function stores in foreign endian, which means it does a @bswap first. pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - @ptrCast(*align(1) T, buf).* = @bswap(T, value); + writeIntNative(T, buf, @bswap(T, value)); } pub const writeIntLittle = switch (builtin.endian) { From 757d0665ae951bdd5cb754adbe433488f0bea8c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 12:03:37 -0500 Subject: [PATCH 028/218] implement comptime pointer cast closes #955 closes #1835 --- src/ir.cpp | 25 ++++++++++++++++++++++--- std/mem.zig | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index dc87f040bc..ef7ad221cf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -166,6 +166,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); +static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -7364,15 +7365,31 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, return ir_add_error_node(ira, source_instruction->source_node, msg); } +// This function takes a comptime ptr and makes the child const value conform to the type +// described by the pointer. +static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, AstNode *source_node, ConstExprValue *ptr_val) { + Error err; + assert(ptr_val->type->id == ZigTypeIdPointer); + ConstExprValue tmp = {}; + tmp.special = ConstValSpecialStatic; + tmp.type = ptr_val->type->data.pointer.child_type; + if ((err = ir_read_const_ptr(ira, source_node, &tmp, ptr_val))) + return err; + ConstExprValue *child_val = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + copy_const_val(child_val, &tmp, false); + return ErrorNone; +} + static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) { + Error err; ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val); assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("TODO handle comptime reinterpreted pointer. See https://github.com/ziglang/zig/issues/955")); - return nullptr; + if ((err = eval_comptime_ptr_reinterpret(ira, source_node, const_val))) + return nullptr; + return const_ptr_pointee_unchecked(ira->codegen, const_val); } return val; } @@ -19990,6 +20007,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { + if (val->special == ConstValSpecialUndef) + val->special = ConstValSpecialStatic; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: diff --git a/std/mem.zig b/std/mem.zig index b9772acd6d..0e51601eb2 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -510,6 +510,15 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); } +test "comptime read/write int" { + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntLittle(u16, &bytes, 0x1234); + const result = std.mem.readIntBig(u16, &bytes); + std.debug.assert(result == 0x3412); + } +} + test "readIntBig and readIntLittle" { assert(readIntSliceBig(u0, []u8{}) == 0x0); assert(readIntSliceLittle(u0, []u8{}) == 0x0); From 5a68c600235fb7cc0e1bf6a8b314e37890e3823b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 12:32:20 -0500 Subject: [PATCH 029/218] ci: update msys packages before installing --- ci/azure/windows_install | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/azure/windows_install b/ci/azure/windows_install index 760520e0b9..8a279210ff 100755 --- a/ci/azure/windows_install +++ b/ci/azure/windows_install @@ -3,7 +3,8 @@ set -x set -e -pacman -S --needed --noconfirm wget p7zip python3-pip openssl +pacman -Su --needed --noconfirm +pacman -S --needed --noconfirm wget p7zip python3-pip pip install s3cmd wget -nv "https://ziglang.org/deps/llvm%2bclang-7.0.0-win64-msvc-release.tar.xz" tar xf llvm+clang-7.0.0-win64-msvc-release.tar.xz From f75262b79f0656ebfac7fb5bd2d6d8e8cce01258 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Dec 2018 11:05:50 -0500 Subject: [PATCH 030/218] fix comptime pointer reinterpretation array index offset closes #1835 --- src/ir.cpp | 9 ++++----- std/mem.zig | 6 ++++++ test/behavior.zig | 1 + test/cases/ptrcast.zig | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/cases/ptrcast.zig diff --git a/src/ir.cpp b/src/ir.cpp index ef7ad221cf..09a9fceabe 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13744,20 +13744,19 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, if (array_val->data.x_array.special != ConstArraySpecialNone) zig_panic("TODO"); size_t elem_size = src_size; - src_size = elem_size * - (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; + src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { ir_add_error_node(ira, source_node, buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", - dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, - src_size)); + dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; } size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); Buf buf = BUF_INIT; buf_resize(&buf, elem_count * elem_size); for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); diff --git a/std/mem.zig b/std/mem.zig index 0e51601eb2..fb5f6fd5da 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -517,6 +517,12 @@ test "comptime read/write int" { const result = std.mem.readIntBig(u16, &bytes); std.debug.assert(result == 0x3412); } + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntBig(u16, &bytes, 0x1234); + const result = std.mem.readIntLittle(u16, &bytes); + std.debug.assert(result == 0x3412); + } } test "readIntBig and readIntLittle" { diff --git a/test/behavior.zig b/test/behavior.zig index 499c20ee20..e32063dec8 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -52,6 +52,7 @@ comptime { _ = @import("cases/optional.zig"); _ = @import("cases/pointers.zig"); _ = @import("cases/popcount.zig"); + _ = @import("cases/ptrcast.zig"); _ = @import("cases/pub_enum/index.zig"); _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("cases/reflection.zig"); diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig new file mode 100644 index 0000000000..071087c5c4 --- /dev/null +++ b/test/cases/ptrcast.zig @@ -0,0 +1,17 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "reinterpret bytes as integer with nonzero offset" { + testReinterpretBytesAsInteger(); + comptime testReinterpretBytesAsInteger(); +} + +fn testReinterpretBytesAsInteger() void { + const bytes = "\x12\x34\x56\x78\xab"; + const expected = switch (builtin.endian) { + builtin.Endian.Little => 0xab785634, + builtin.Endian.Big => 0x345678ab, + }; + assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); +} From e077a446566b0aa77a121f9554f3cb355899653a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Dec 2018 15:48:26 -0500 Subject: [PATCH 031/218] ir: delete dead code --- src/all_types.hpp | 1 - src/codegen.cpp | 26 -------------------------- src/ir.cpp | 3 +-- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 83b7e8495f..11304e536d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -605,7 +605,6 @@ enum CastOp { CastOpFloatToInt, CastOpBoolToInt, CastOpResizeSlice, - CastOpBytesToSlice, CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, diff --git a/src/codegen.cpp b/src/codegen.cpp index 08dd11800a..e37703d5f0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2882,32 +2882,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - return cast_instruction->tmp_ptr; - } - case CastOpBytesToSlice: - { - assert(cast_instruction->tmp_ptr); - assert(wanted_type->id == ZigTypeIdStruct); - assert(wanted_type->data.structure.is_slice); - assert(actual_type->id == ZigTypeIdArray); - - ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; - ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type; - - - size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index; - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_ptr_index, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, ""); - gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); - - size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index; - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_len_index, ""); - LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, - actual_type->data.array.len / type_size(g, wanted_child_type), false); - gen_store_untyped(g, len_val, len_ptr, 0, false); - return cast_instruction->tmp_ptr; } case CastOpIntToFloat: diff --git a/src/ir.cpp b/src/ir.cpp index 09a9fceabe..76dd6c6391 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9339,7 +9339,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ const_val->type = new_type; break; case CastOpResizeSlice: - case CastOpBytesToSlice: // can't do it zig_unreachable(); case CastOpIntToFloat: @@ -9396,7 +9395,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst ZigType *wanted_type, CastOp cast_op, bool need_alloca) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && - cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice) + cast_op != CastOpResizeSlice) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); From f6a02a427f6f81e531f05624ee353872e2de7d99 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Dec 2018 15:55:00 -0500 Subject: [PATCH 032/218] README: clarify self-hosted status --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a19e9eb67a..c1eec599e5 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,8 @@ See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows *Note: Stage 2 compiler is not complete. Beta users of Zig should use the Stage 1 compiler for now.* -Dependencies are the same as Stage 1, except now you have a working zig compiler. +Dependencies are the same as Stage 1, except now you can use stage 1 to compile +Zig code. ``` bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install @@ -183,11 +184,13 @@ binary. ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler -This is the actual compiler binary that we will install to the system. - *Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is not yet supported.* +Once the self-hosted compiler can build itself, this will be the actual +compiler binary that we will install to the system. Until then, users should +use stage 1. + #### Debug / Development Build ``` From 260c3d9cc0c85c1c4dce98bda9e15ca49ca87d74 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 11:50:29 +0100 Subject: [PATCH 033/218] formatType can now format comptime_int --- std/fmt/index.zig | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index eda0bfae03..adf2882f35 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -117,7 +117,7 @@ pub fn formatType( return output(context, @errorName(value)); } switch (@typeInfo(T)) { - builtin.TypeId.Int, builtin.TypeId.Float => { + builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => { return formatValue(value, fmt, context, Errors, output); }, builtin.TypeId.Void => { @@ -268,11 +268,15 @@ fn formatValue( } } - comptime var T = @typeOf(value); + 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), - else => unreachable, + builtin.TypeId.ComptimeInt => { + const Int = math.IntFittingRange(value, value); + return formatIntValue(Int(value), fmt, context, Errors, output); + }, + else => comptime unreachable, } } @@ -289,9 +293,10 @@ pub fn formatIntValue( if (fmt.len > 0) { switch (fmt[0]) { 'c' => { - if (@typeOf(value) == u8) { - if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]}); - return formatAsciiChar(value, context, Errors, output); + 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' => { @@ -964,6 +969,25 @@ test "fmt.format" { 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]; + assert(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]; + debug.warn("{}\n", res); + assert(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]; + debug.warn("{}\n", res); + assert(mem.eql(u8, res, "1100")); + } { const value: [3]u8 = "abc"; try testFmt("array: abc\n", "array: {}\n", value); @@ -985,6 +1009,10 @@ test "fmt.format" { 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); + } 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"); From 45e72c0b3944b2fa6d06c7018e9648b4ae60006a Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 15:39:18 +0100 Subject: [PATCH 034/218] Fixed intToPtr to fn type when the address is hardcoded (#1842) * Fixed intToPtr to fn type * Added test * Import inttoptr.zig in behavior.zig --- src/ir.cpp | 1 + test/behavior.zig | 1 + test/cases/inttoptr.zig | 13 +++++++++++++ 3 files changed, 15 insertions(+) create mode 100644 test/cases/inttoptr.zig diff --git a/src/ir.cpp b/src/ir.cpp index 76dd6c6391..028582f87f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12495,6 +12495,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct case ReqCompTimeNo: if (casted_init_value->value.special == ConstValSpecialStatic && casted_init_value->value.type->id == ZigTypeIdFn && + casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) { var_class_requires_const = true; diff --git a/test/behavior.zig b/test/behavior.zig index e32063dec8..8090359772 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -42,6 +42,7 @@ comptime { _ = @import("cases/if.zig"); _ = @import("cases/import.zig"); _ = @import("cases/incomplete_struct_param_tld.zig"); + _ = @import("cases/inttoptr.zig"); _ = @import("cases/ir_block_deps.zig"); _ = @import("cases/math.zig"); _ = @import("cases/merge_error_sets.zig"); diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig new file mode 100644 index 0000000000..6695352383 --- /dev/null +++ b/test/cases/inttoptr.zig @@ -0,0 +1,13 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "casting random address to function pointer" { + randomAddressToFunction(); + comptime randomAddressToFunction(); +} + +fn randomAddressToFunction() void { + var addr: usize = 0xdeadbeef; + var ptr = @intToPtr(fn () void, addr); +} From a7670e80a49021fb96d1f9a1bbcbcfc6c1e835ab Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 16:07:35 +0100 Subject: [PATCH 035/218] Added formatting of function pointers (#1843) --- std/fmt/index.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index adf2882f35..b010072273 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -243,6 +243,9 @@ pub fn formatType( } 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) ++ "'"), } } @@ -1013,6 +1016,10 @@ test "fmt.format" { 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"); From 666b153144eeb160c5b2279d406f8e0b23613857 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Mon, 17 Dec 2018 17:48:34 -0200 Subject: [PATCH 036/218] freebsd: remove syscall files --- CMakeLists.txt | 2 - std/c/freebsd.zig | 39 ++- std/os/freebsd/index.zig | 4 +- std/os/freebsd/syscall.zig | 493 ------------------------------------- std/os/freebsd/x86_64.zig | 136 ---------- 5 files changed, 39 insertions(+), 635 deletions(-) delete mode 100644 std/os/freebsd/syscall.zig delete mode 100644 std/os/freebsd/x86_64.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b64bcca81..a9a4d8faa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -586,8 +586,6 @@ set(ZIG_STD_FILES "os/linux/arm64.zig" "os/freebsd/errno.zig" "os/freebsd/index.zig" - "os/freebsd/syscall.zig" - "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" "os/windows/advapi32.zig" diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 421e964827..a97cf52eb9 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -1,5 +1,3 @@ -const timespec = @import("../os/freebsd/index.zig").timespec; - extern "c" fn __error() *c_int; pub const _errno = __error; @@ -31,3 +29,40 @@ pub const pthread_attr_t = extern struct { __size: [56]u8, __align: c_long, }; + +pub const msghdr = extern struct { + msg_name: *u8, + msg_namelen: socklen_t, + msg_iov: *iovec, + msg_iovlen: i32, + __pad1: i32, + msg_control: *u8, + msg_controllen: socklen_t, + __pad2: socklen_t, + msg_flags: i32, +}; + +pub const Stat = extern struct { + dev: u64, + ino: u64, + nlink: usize, + + mode: u32, + uid: u32, + gid: u32, + __pad0: u32, + rdev: u64, + size: i64, + blksize: isize, + blocks: i64, + + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]isize, +}; + +pub const timespec = extern struct { + tv_sec: isize, + tv_nsec: isize, +}; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 34a3414a48..975479c1e0 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -742,8 +742,8 @@ pub fn raise(sig: i32) usize { return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig))); } -pub const Stat = arch.Stat; -pub const timespec = arch.timespec; +pub const Stat = c.Stat; +pub const timespec = c.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); diff --git a/std/os/freebsd/syscall.zig b/std/os/freebsd/syscall.zig deleted file mode 100644 index 6cdd71de3b..0000000000 --- a/std/os/freebsd/syscall.zig +++ /dev/null @@ -1,493 +0,0 @@ -pub const SYS_syscall = 0; -pub const SYS_exit = 1; -pub const SYS_fork = 2; -pub const SYS_read = 3; -pub const SYS_write = 4; -pub const SYS_open = 5; -pub const SYS_close = 6; -pub const SYS_wait4 = 7; -// 8 is old creat -pub const SYS_link = 9; -pub const SYS_unlink = 10; -// 11 is obsolete execv -pub const SYS_chdir = 12; -pub const SYS_fchdir = 13; -pub const SYS_freebsd11_mknod = 14; -pub const SYS_chmod = 15; -pub const SYS_chown = 16; -pub const SYS_break = 17; -// 18 is freebsd4 getfsstat -// 19 is old lseek -pub const SYS_getpid = 20; -pub const SYS_mount = 21; -pub const SYS_unmount = 22; -pub const SYS_setuid = 23; -pub const SYS_getuid = 24; -pub const SYS_geteuid = 25; -pub const SYS_ptrace = 26; -pub const SYS_recvmsg = 27; -pub const SYS_sendmsg = 28; -pub const SYS_recvfrom = 29; -pub const SYS_accept = 30; -pub const SYS_getpeername = 31; -pub const SYS_getsockname = 32; -pub const SYS_access = 33; -pub const SYS_chflags = 34; -pub const SYS_fchflags = 35; -pub const SYS_sync = 36; -pub const SYS_kill = 37; -// 38 is old stat -pub const SYS_getppid = 39; -// 40 is old lstat -pub const SYS_dup = 41; -pub const SYS_freebsd10_pipe = 42; -pub const SYS_getegid = 43; -pub const SYS_profil = 44; -pub const SYS_ktrace = 45; -// 46 is old sigaction -pub const SYS_getgid = 47; -// 48 is old sigprocmask -pub const SYS_getlogin = 49; -pub const SYS_setlogin = 50; -pub const SYS_acct = 51; -// 52 is old sigpending -pub const SYS_sigaltstack = 53; -pub const SYS_ioctl = 54; -pub const SYS_reboot = 55; -pub const SYS_revoke = 56; -pub const SYS_symlink = 57; -pub const SYS_readlink = 58; -pub const SYS_execve = 59; -pub const SYS_umask = 60; -pub const SYS_chroot = 61; -// 62 is old fstat -// 63 is old getkerninfo -// 64 is old getpagesize -pub const SYS_msync = 65; -pub const SYS_vfork = 66; -// 67 is obsolete vread -// 68 is obsolete vwrite -// 69 is obsolete sbrk (still present on some platforms) -pub const SYS_sstk = 70; -// 71 is old mmap -pub const SYS_vadvise = 72; -pub const SYS_munmap = 73; -pub const SYS_mprotect = 74; -pub const SYS_madvise = 75; -// 76 is obsolete vhangup -// 77 is obsolete vlimit -pub const SYS_mincore = 78; -pub const SYS_getgroups = 79; -pub const SYS_setgroups = 80; -pub const SYS_getpgrp = 81; -pub const SYS_setpgid = 82; -pub const SYS_setitimer = 83; -// 84 is old wait -pub const SYS_swapon = 85; -pub const SYS_getitimer = 86; -// 87 is old gethostname -// 88 is old sethostname -pub const SYS_getdtablesize = 89; -pub const SYS_dup2 = 90; -pub const SYS_fcntl = 92; -pub const SYS_select = 93; -pub const SYS_fsync = 95; -pub const SYS_setpriority = 96; -pub const SYS_socket = 97; -pub const SYS_connect = 98; -// 99 is old accept -pub const SYS_getpriority = 100; -// 101 is old send -// 102 is old recv -// 103 is old sigreturn -pub const SYS_bind = 104; -pub const SYS_setsockopt = 105; -pub const SYS_listen = 106; -// 107 is obsolete vtimes -// 108 is old sigvec -// 109 is old sigblock -// 110 is old sigsetmask -// 111 is old sigsuspend -// 112 is old sigstack -// 113 is old recvmsg -// 114 is old sendmsg -// 115 is obsolete vtrace -pub const SYS_gettimeofday = 116; -pub const SYS_getrusage = 117; -pub const SYS_getsockopt = 118; -pub const SYS_readv = 120; -pub const SYS_writev = 121; -pub const SYS_settimeofday = 122; -pub const SYS_fchown = 123; -pub const SYS_fchmod = 124; -// 125 is old recvfrom -pub const SYS_setreuid = 126; -pub const SYS_setregid = 127; -pub const SYS_rename = 128; -// 129 is old truncate -// 130 is old ftruncate -pub const SYS_flock = 131; -pub const SYS_mkfifo = 132; -pub const SYS_sendto = 133; -pub const SYS_shutdown = 134; -pub const SYS_socketpair = 135; -pub const SYS_mkdir = 136; -pub const SYS_rmdir = 137; -pub const SYS_utimes = 138; -// 139 is obsolete 4.2 sigreturn -pub const SYS_adjtime = 140; -// 141 is old getpeername -// 142 is old gethostid -// 143 is old sethostid -// 144 is old getrlimit -// 145 is old setrlimit -// 146 is old killpg -pub const SYS_setsid = 147; -pub const SYS_quotactl = 148; -// 149 is old quota -// 150 is old getsockname -pub const SYS_nlm_syscall = 154; -pub const SYS_nfssvc = 155; -// 156 is old getdirentries -// 157 is freebsd4 statfs -// 158 is freebsd4 fstatfs -pub const SYS_lgetfh = 160; -pub const SYS_getfh = 161; -// 162 is freebsd4 getdomainname -// 163 is freebsd4 setdomainname -// 164 is freebsd4 uname -pub const SYS_sysarch = 165; -pub const SYS_rtprio = 166; -pub const SYS_semsys = 169; -pub const SYS_msgsys = 170; -pub const SYS_shmsys = 171; -// 173 is freebsd6 pread -// 174 is freebsd6 pwrite -pub const SYS_setfib = 175; -pub const SYS_ntp_adjtime = 176; -pub const SYS_setgid = 181; -pub const SYS_setegid = 182; -pub const SYS_seteuid = 183; -// 184 is obsolete lfs_bmapv -// 185 is obsolete lfs_markv -// 186 is obsolete lfs_segclean -// 187 is obsolete lfs_segwait -pub const SYS_freebsd11_stat = 188; -pub const SYS_freebsd11_fstat = 189; -pub const SYS_freebsd11_lstat = 190; -pub const SYS_pathconf = 191; -pub const SYS_fpathconf = 192; -pub const SYS_getrlimit = 194; -pub const SYS_setrlimit = 195; -pub const SYS_freebsd11_getdirentries = 196; -// 197 is freebsd6 mmap -pub const SYS___syscall = 198; -// 199 is freebsd6 lseek -// 200 is freebsd6 truncate -// 201 is freebsd6 ftruncate -pub const SYS___sysctl = 202; -pub const SYS_mlock = 203; -pub const SYS_munlock = 204; -pub const SYS_undelete = 205; -pub const SYS_futimes = 206; -pub const SYS_getpgid = 207; -pub const SYS_poll = 209; -pub const SYS_freebsd7___semctl = 220; -pub const SYS_semget = 221; -pub const SYS_semop = 222; -pub const SYS_freebsd7_msgctl = 224; -pub const SYS_msgget = 225; -pub const SYS_msgsnd = 226; -pub const SYS_msgrcv = 227; -pub const SYS_shmat = 228; -pub const SYS_freebsd7_shmctl = 229; -pub const SYS_shmdt = 230; -pub const SYS_shmget = 231; -pub const SYS_clock_gettime = 232; -pub const SYS_clock_settime = 233; -pub const SYS_clock_getres = 234; -pub const SYS_ktimer_create = 235; -pub const SYS_ktimer_delete = 236; -pub const SYS_ktimer_settime = 237; -pub const SYS_ktimer_gettime = 238; -pub const SYS_ktimer_getoverrun = 239; -pub const SYS_nanosleep = 240; -pub const SYS_ffclock_getcounter = 241; -pub const SYS_ffclock_setestimate = 242; -pub const SYS_ffclock_getestimate = 243; -pub const SYS_clock_nanosleep = 244; -pub const SYS_clock_getcpuclockid2 = 247; -pub const SYS_ntp_gettime = 248; -pub const SYS_minherit = 250; -pub const SYS_rfork = 251; -// 252 is obsolete openbsd_poll -pub const SYS_issetugid = 253; -pub const SYS_lchown = 254; -pub const SYS_aio_read = 255; -pub const SYS_aio_write = 256; -pub const SYS_lio_listio = 257; -pub const SYS_freebsd11_getdents = 272; -pub const SYS_lchmod = 274; -// 275 is obsolete netbsd_lchown -pub const SYS_lutimes = 276; -// 277 is obsolete netbsd_msync -pub const SYS_freebsd11_nstat = 278; -pub const SYS_freebsd11_nfstat = 279; -pub const SYS_freebsd11_nlstat = 280; -pub const SYS_preadv = 289; -pub const SYS_pwritev = 290; -// 297 is freebsd4 fhstatfs -pub const SYS_fhopen = 298; -pub const SYS_freebsd11_fhstat = 299; -pub const SYS_modnext = 300; -pub const SYS_modstat = 301; -pub const SYS_modfnext = 302; -pub const SYS_modfind = 303; -pub const SYS_kldload = 304; -pub const SYS_kldunload = 305; -pub const SYS_kldfind = 306; -pub const SYS_kldnext = 307; -pub const SYS_kldstat = 308; -pub const SYS_kldfirstmod = 309; -pub const SYS_getsid = 310; -pub const SYS_setresuid = 311; -pub const SYS_setresgid = 312; -// 313 is obsolete signanosleep -pub const SYS_aio_return = 314; -pub const SYS_aio_suspend = 315; -pub const SYS_aio_cancel = 316; -pub const SYS_aio_error = 317; -// 318 is freebsd6 aio_read -// 319 is freebsd6 aio_write -// 320 is freebsd6 lio_listio -pub const SYS_yield = 321; -// 322 is obsolete thr_sleep -// 323 is obsolete thr_wakeup -pub const SYS_mlockall = 324; -pub const SYS_munlockall = 325; -pub const SYS___getcwd = 326; -pub const SYS_sched_setparam = 327; -pub const SYS_sched_getparam = 328; -pub const SYS_sched_setscheduler = 329; -pub const SYS_sched_getscheduler = 330; -pub const SYS_sched_yield = 331; -pub const SYS_sched_get_priority_max = 332; -pub const SYS_sched_get_priority_min = 333; -pub const SYS_sched_rr_get_interval = 334; -pub const SYS_utrace = 335; -// 336 is freebsd4 sendfile -pub const SYS_kldsym = 337; -pub const SYS_jail = 338; -pub const SYS_nnpfs_syscall = 339; -pub const SYS_sigprocmask = 340; -pub const SYS_sigsuspend = 341; -// 342 is freebsd4 sigaction -pub const SYS_sigpending = 343; -// 344 is freebsd4 sigreturn -pub const SYS_sigtimedwait = 345; -pub const SYS_sigwaitinfo = 346; -pub const SYS___acl_get_file = 347; -pub const SYS___acl_set_file = 348; -pub const SYS___acl_get_fd = 349; -pub const SYS___acl_set_fd = 350; -pub const SYS___acl_delete_file = 351; -pub const SYS___acl_delete_fd = 352; -pub const SYS___acl_aclcheck_file = 353; -pub const SYS___acl_aclcheck_fd = 354; -pub const SYS_extattrctl = 355; -pub const SYS_extattr_set_file = 356; -pub const SYS_extattr_get_file = 357; -pub const SYS_extattr_delete_file = 358; -pub const SYS_aio_waitcomplete = 359; -pub const SYS_getresuid = 360; -pub const SYS_getresgid = 361; -pub const SYS_kqueue = 362; -pub const SYS_freebsd11_kevent = 363; -// 364 is obsolete __cap_get_proc -// 365 is obsolete __cap_set_proc -// 366 is obsolete __cap_get_fd -// 367 is obsolete __cap_get_file -// 368 is obsolete __cap_set_fd -// 369 is obsolete __cap_set_file -pub const SYS_extattr_set_fd = 371; -pub const SYS_extattr_get_fd = 372; -pub const SYS_extattr_delete_fd = 373; -pub const SYS___setugid = 374; -pub const SYS_eaccess = 376; -pub const SYS_afs3_syscall = 377; -pub const SYS_nmount = 378; -// 379 is obsolete kse_exit -// 380 is obsolete kse_wakeup -// 381 is obsolete kse_create -// 382 is obsolete kse_thr_interrupt -// 383 is obsolete kse_release -pub const SYS___mac_get_proc = 384; -pub const SYS___mac_set_proc = 385; -pub const SYS___mac_get_fd = 386; -pub const SYS___mac_get_file = 387; -pub const SYS___mac_set_fd = 388; -pub const SYS___mac_set_file = 389; -pub const SYS_kenv = 390; -pub const SYS_lchflags = 391; -pub const SYS_uuidgen = 392; -pub const SYS_sendfile = 393; -pub const SYS_mac_syscall = 394; -pub const SYS_freebsd11_getfsstat = 395; -pub const SYS_freebsd11_statfs = 396; -pub const SYS_freebsd11_fstatfs = 397; -pub const SYS_freebsd11_fhstatfs = 398; -pub const SYS_ksem_close = 400; -pub const SYS_ksem_post = 401; -pub const SYS_ksem_wait = 402; -pub const SYS_ksem_trywait = 403; -pub const SYS_ksem_init = 404; -pub const SYS_ksem_open = 405; -pub const SYS_ksem_unlink = 406; -pub const SYS_ksem_getvalue = 407; -pub const SYS_ksem_destroy = 408; -pub const SYS___mac_get_pid = 409; -pub const SYS___mac_get_link = 410; -pub const SYS___mac_set_link = 411; -pub const SYS_extattr_set_link = 412; -pub const SYS_extattr_get_link = 413; -pub const SYS_extattr_delete_link = 414; -pub const SYS___mac_execve = 415; -pub const SYS_sigaction = 416; -pub const SYS_sigreturn = 417; -pub const SYS_getcontext = 421; -pub const SYS_setcontext = 422; -pub const SYS_swapcontext = 423; -pub const SYS_swapoff = 424; -pub const SYS___acl_get_link = 425; -pub const SYS___acl_set_link = 426; -pub const SYS___acl_delete_link = 427; -pub const SYS___acl_aclcheck_link = 428; -pub const SYS_sigwait = 429; -pub const SYS_thr_create = 430; -pub const SYS_thr_exit = 431; -pub const SYS_thr_self = 432; -pub const SYS_thr_kill = 433; -pub const SYS_jail_attach = 436; -pub const SYS_extattr_list_fd = 437; -pub const SYS_extattr_list_file = 438; -pub const SYS_extattr_list_link = 439; -// 440 is obsolete kse_switchin -pub const SYS_ksem_timedwait = 441; -pub const SYS_thr_suspend = 442; -pub const SYS_thr_wake = 443; -pub const SYS_kldunloadf = 444; -pub const SYS_audit = 445; -pub const SYS_auditon = 446; -pub const SYS_getauid = 447; -pub const SYS_setauid = 448; -pub const SYS_getaudit = 449; -pub const SYS_setaudit = 450; -pub const SYS_getaudit_addr = 451; -pub const SYS_setaudit_addr = 452; -pub const SYS_auditctl = 453; -pub const SYS__umtx_op = 454; -pub const SYS_thr_new = 455; -pub const SYS_sigqueue = 456; -pub const SYS_kmq_open = 457; -pub const SYS_kmq_setattr = 458; -pub const SYS_kmq_timedreceive = 459; -pub const SYS_kmq_timedsend = 460; -pub const SYS_kmq_notify = 461; -pub const SYS_kmq_unlink = 462; -pub const SYS_abort2 = 463; -pub const SYS_thr_set_name = 464; -pub const SYS_aio_fsync = 465; -pub const SYS_rtprio_thread = 466; -pub const SYS_sctp_peeloff = 471; -pub const SYS_sctp_generic_sendmsg = 472; -pub const SYS_sctp_generic_sendmsg_iov = 473; -pub const SYS_sctp_generic_recvmsg = 474; -pub const SYS_pread = 475; -pub const SYS_pwrite = 476; -pub const SYS_mmap = 477; -pub const SYS_lseek = 478; -pub const SYS_truncate = 479; -pub const SYS_ftruncate = 480; -pub const SYS_thr_kill2 = 481; -pub const SYS_shm_open = 482; -pub const SYS_shm_unlink = 483; -pub const SYS_cpuset = 484; -pub const SYS_cpuset_setid = 485; -pub const SYS_cpuset_getid = 486; -pub const SYS_cpuset_getaffinity = 487; -pub const SYS_cpuset_setaffinity = 488; -pub const SYS_faccessat = 489; -pub const SYS_fchmodat = 490; -pub const SYS_fchownat = 491; -pub const SYS_fexecve = 492; -pub const SYS_freebsd11_fstatat = 493; -pub const SYS_futimesat = 494; -pub const SYS_linkat = 495; -pub const SYS_mkdirat = 496; -pub const SYS_mkfifoat = 497; -pub const SYS_freebsd11_mknodat = 498; -pub const SYS_openat = 499; -pub const SYS_readlinkat = 500; -pub const SYS_renameat = 501; -pub const SYS_symlinkat = 502; -pub const SYS_unlinkat = 503; -pub const SYS_posix_openpt = 504; -pub const SYS_gssd_syscall = 505; -pub const SYS_jail_get = 506; -pub const SYS_jail_set = 507; -pub const SYS_jail_remove = 508; -pub const SYS_closefrom = 509; -pub const SYS___semctl = 510; -pub const SYS_msgctl = 511; -pub const SYS_shmctl = 512; -pub const SYS_lpathconf = 513; -// 514 is obsolete cap_new -pub const SYS___cap_rights_get = 515; -pub const SYS_cap_enter = 516; -pub const SYS_cap_getmode = 517; -pub const SYS_pdfork = 518; -pub const SYS_pdkill = 519; -pub const SYS_pdgetpid = 520; -pub const SYS_pselect = 522; -pub const SYS_getloginclass = 523; -pub const SYS_setloginclass = 524; -pub const SYS_rctl_get_racct = 525; -pub const SYS_rctl_get_rules = 526; -pub const SYS_rctl_get_limits = 527; -pub const SYS_rctl_add_rule = 528; -pub const SYS_rctl_remove_rule = 529; -pub const SYS_posix_fallocate = 530; -pub const SYS_posix_fadvise = 531; -pub const SYS_wait6 = 532; -pub const SYS_cap_rights_limit = 533; -pub const SYS_cap_ioctls_limit = 534; -pub const SYS_cap_ioctls_get = 535; -pub const SYS_cap_fcntls_limit = 536; -pub const SYS_cap_fcntls_get = 537; -pub const SYS_bindat = 538; -pub const SYS_connectat = 539; -pub const SYS_chflagsat = 540; -pub const SYS_accept4 = 541; -pub const SYS_pipe2 = 542; -pub const SYS_aio_mlock = 543; -pub const SYS_procctl = 544; -pub const SYS_ppoll = 545; -pub const SYS_futimens = 546; -pub const SYS_utimensat = 547; -// 548 is obsolete numa_getaffinity -// 549 is obsolete numa_setaffinity -pub const SYS_fdatasync = 550; -pub const SYS_fstat = 551; -pub const SYS_fstatat = 552; -pub const SYS_fhstat = 553; -pub const SYS_getdirentries = 554; -pub const SYS_statfs = 555; -pub const SYS_fstatfs = 556; -pub const SYS_getfsstat = 557; -pub const SYS_fhstatfs = 558; -pub const SYS_mknodat = 559; -pub const SYS_kevent = 560; -pub const SYS_cpuset_getdomain = 561; -pub const SYS_cpuset_setdomain = 562; -pub const SYS_getrandom = 563; -pub const SYS_MAXSYSCALL = 564; diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig deleted file mode 100644 index 509075386f..0000000000 --- a/std/os/freebsd/x86_64.zig +++ /dev/null @@ -1,136 +0,0 @@ -const freebsd = @import("index.zig"); -const socklen_t = freebsd.socklen_t; -const iovec = freebsd.iovec; - -pub const SYS_sbrk = 69; - -pub fn syscall0(number: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number) - : "rcx", "r11" - ); -} - -pub fn syscall1(number: usize, arg1: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1) - : "rcx", "r11" - ); -} - -pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2) - : "rcx", "r11" - ); -} - -pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3) - : "rcx", "r11" - ); -} - -pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4) - : "rcx", "r11" - ); -} - -pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4), - [arg5] "{r8}" (arg5) - : "rcx", "r11" - ); -} - -pub fn syscall6( - number: usize, - arg1: usize, - arg2: usize, - arg3: usize, - arg4: usize, - arg5: usize, - arg6: usize, -) usize { - return asm volatile ("syscall" - : [ret] "={rax}" (-> usize) - : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4), - [arg5] "{r8}" (arg5), - [arg6] "{r9}" (arg6) - : "rcx", "r11" - ); -} - -pub nakedcc fn restore_rt() void { - asm volatile ("syscall" - : - : [number] "{rax}" (usize(SYS_rt_sigreturn)) - : "rcx", "r11" - ); -} - -pub const msghdr = extern struct { - msg_name: *u8, - msg_namelen: socklen_t, - msg_iov: *iovec, - msg_iovlen: i32, - __pad1: i32, - msg_control: *u8, - msg_controllen: socklen_t, - __pad2: socklen_t, - msg_flags: i32, -}; - -/// Renamed to Stat to not conflict with the stat function. -pub const Stat = extern struct { - dev: u64, - ino: u64, - nlink: usize, - - mode: u32, - uid: u32, - gid: u32, - __pad0: u32, - rdev: u64, - size: i64, - blksize: isize, - blocks: i64, - - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [3]isize, -}; - -pub const timespec = extern struct { - tv_sec: isize, - tv_nsec: isize, -}; From 5ea37f6e8c9226ec02fbc95cc5c6d06a8e9ee6f7 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Mon, 17 Dec 2018 22:06:28 -0200 Subject: [PATCH 037/218] freebsd: add getdirentries --- std/c/freebsd.zig | 12 +++++++++ std/os/freebsd/index.zig | 5 ++++ std/os/index.zig | 53 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index a97cf52eb9..fbcd6236f0 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -13,6 +13,7 @@ pub extern "c" fn kevent( pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; +pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { @@ -66,3 +67,14 @@ pub const timespec = extern struct { tv_sec: isize, tv_nsec: isize, }; + +pub const dirent = extern struct { + d_fileno: usize, + d_off: i64, + d_reclen: u64, + d_type: u8, + d_pad0: u8, + d_namlen: u16, + d_pad1: u16, + d_name: [256]u8, +}; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 975479c1e0..880a49b4a8 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -562,6 +562,10 @@ pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), 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 isatty(fd: i32) bool { var wsz: winsize = undefined; return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; @@ -743,6 +747,7 @@ pub fn raise(sig: i32) usize { } pub const Stat = c.Stat; +pub const dirent = c.dirent; pub const timespec = c.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { diff --git a/std/os/index.zig b/std/os/index.zig index be82ad4716..778ab156b0 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -1753,8 +1753,57 @@ pub const Dir = struct { } fn nextFreebsd(self: *Dir) !?Entry { - //self.handle.buf = try self.allocator.alloc(u8, page_size); - @compileError("TODO implement dirs for FreeBSD"); + 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, + }; + } } }; From 0273fbf710f98854f3331c0810cd2f31f20d2fb5 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Mon, 17 Dec 2018 22:07:21 -0200 Subject: [PATCH 038/218] freebsd: add access --- std/os/freebsd/index.zig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 880a49b4a8..73573d1d21 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -95,6 +95,13 @@ 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 = 0o0; pub const O_WRONLY = 0o1; pub const O_RDWR = 0o2; @@ -554,6 +561,10 @@ pub fn fork() usize { return arch.syscall0(SYS_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 arch.syscall2(SYS___getcwd, @ptrToInt(buf), size); } From 1fc56b82ad6f1060ec4b2074c16accfe0327a4b7 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 00:19:20 -0200 Subject: [PATCH 039/218] freebsd: link against libc Since the stable kernel ABI is through libc #1759 --- src/analyze.cpp | 2 +- src/codegen.cpp | 3 ++- std/special/bootstrap.zig | 15 ++++----------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 46686ce772..064cf11cc1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6366,7 +6366,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { if (is_libc && g->libc_link_lib != nullptr) return g->libc_link_lib; - if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS) { + if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS && g->zig_target.os != OsFreeBSD) { fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n" "Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n"); exit(1); diff --git a/src/codegen.cpp b/src/codegen.cpp index e37703d5f0..e2d23513ff 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -178,7 +178,8 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out // On Darwin/MacOS/iOS, we always link libSystem which contains libc. if (g->zig_target.os == OsMacOSX || - g->zig_target.os == OsIOS) + g->zig_target.os == OsIOS || + g->zig_target.os == OsFreeBSD) { g->libc_link_lib = create_link_lib(buf_create_from_str("c")); g->link_libs_list.append(g->libc_link_lib); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index a15be317ab..129bde913f 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -20,17 +20,10 @@ comptime { nakedcc fn _start() noreturn { switch (builtin.arch) { - builtin.Arch.x86_64 => switch (builtin.os) { - builtin.Os.freebsd => { - argc_ptr = asm ("lea (%%rdi), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, - else => { - argc_ptr = asm ("lea (%%rsp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, + builtin.Arch.x86_64 => { + argc_ptr = asm ("lea (%%rsp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); }, builtin.Arch.i386 => { argc_ptr = asm ("lea (%%esp), %[argc]" From 6cfcdbde2b902476863cb912190f20ce5e02277c Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 00:19:52 -0200 Subject: [PATCH 040/218] freebsd: link against libc++ All supported versions of FreeBSD have libc++ in the base system. --- build.zig | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index e411ae8b21..2a51203ff7 100644 --- a/build.zig +++ b/build.zig @@ -293,11 +293,17 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { try addCxxKnownPath(b, ctx, exe, "libstdc++.a", \\Unable to determine path to libstdc++.a \\On Fedora, install libstdc++-static and try again. - \\ ); exe.linkSystemLibrary("pthread"); - } else if (exe.target.isDarwin() or exe.target.isFreeBSD()) { + } else if (exe.target.isFreeBSD()) { + try addCxxKnownPath(b, ctx, exe, "libc++.a", null); + exe.linkSystemLibrary("pthread"); + // TODO LLD cannot perform this link. + // See https://github.com/ziglang/zig/issues/1535 + exe.enableSystemLinkerHack(); + } + else if (exe.target.isDarwin()) { if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { // Compiler is GCC. try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); From 11ced4f99d95ec144d9dbb79ead335b571f714fe Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 01:32:35 -0200 Subject: [PATCH 041/218] freebsd: use libc interface instead system calls Remove all syscalls references * dup2() * chdir() * execve() * fork() * getcwd() * isatty() * readlink() * mkdir() * mmap() * munmap() * read() * rmdir() * symlink() * pread() * write() * pwrite() * rename() * open() * close() * lseek() * exit() * unlink() * waitpid() * nanosleep() * setreuid() * setregid() * raise() * fstat() * pipe() * added pipe2() extern c fn --- std/c/freebsd.zig | 2 + std/os/freebsd/index.zig | 114 +++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index fbcd6236f0..32cd48748c 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -14,6 +14,8 @@ pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlen pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; +pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; +pub extern "c" fn getrandom(buf: [*]u8, count: usize, flags: u32) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 73573d1d21..9191dc3219 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -1,14 +1,11 @@ -const assert = @import("../debug.zig").assert; const builtin = @import("builtin"); -const arch = switch (builtin.arch) { - builtin.Arch.x86_64 => @import("x86_64.zig"), - else => @compileError("unsupported arch"), -}; -pub use @import("syscall.zig"); + 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; @@ -546,19 +543,19 @@ pub fn getErrno(r: usize) usize { } pub fn dup2(old: i32, new: i32) usize { - return arch.syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); + return errnoWrap(c.dup2(old, new)); } pub fn chdir(path: [*]const u8) usize { - return arch.syscall1(SYS_chdir, @ptrToInt(path)); + return errnoWrap(c.chdir(path)); } pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { - return arch.syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); + return errnoWrap(c.execve(path, argv, envp)); } pub fn fork() usize { - return arch.syscall0(SYS_fork); + return errnoWrap(c.fork()); } pub fn access(path: [*]const u8, mode: u32) usize { @@ -566,7 +563,7 @@ pub fn access(path: [*]const u8, mode: u32) usize { } pub fn getcwd(buf: [*]u8, size: usize) usize { - return arch.syscall2(SYS___getcwd, @ptrToInt(buf), size); + return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0; } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { @@ -578,40 +575,48 @@ pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize } pub fn isatty(fd: i32) bool { - var wsz: winsize = undefined; - return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return c.isatty(fd) != 0; } pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { - return arch.syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); + return errnoWrap(c.readlink(path, buf_ptr, buf_len)); } pub fn mkdir(path: [*]const u8, mode: u32) usize { - return arch.syscall2(SYS_mkdir, @ptrToInt(path), mode); + return errnoWrap(c.mkdir(path, mode)); } -pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { - return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); +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 arch.syscall2(SYS_munmap, address, length); + return errnoWrap(c.munmap(@intToPtr(*c_void, address), length)); } -pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return arch.syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); +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 arch.syscall1(SYS_rmdir, @ptrToInt(path)); + return errnoWrap(c.rmdir(path)); } pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { - return arch.syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); + return errnoWrap(c.symlink(existing, new)); } -pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); +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 { @@ -622,16 +627,17 @@ pub fn pipe(fd: *[2]i32) usize { return pipe2(fd, 0); } -pub fn pipe2(fd: *[2]i32, flags: usize) usize { - return arch.syscall2(SYS_pipe2, @ptrToInt(fd), flags); +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, count: usize) usize { - return arch.syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); +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, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); +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 { @@ -639,11 +645,11 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) } pub fn rename(old: [*]const u8, new: [*]const u8) usize { - return arch.syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); + return errnoWrap(c.rename(old, new)); } -pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { - return arch.syscall3(SYS_open, @ptrToInt(path), flags, perm); +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 { @@ -655,20 +661,19 @@ pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { } pub fn close(fd: i32) usize { - return arch.syscall1(SYS_close, @bitCast(usize, isize(fd))); + return errnoWrap(c.close(fd)); } -pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return arch.syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); +pub fn lseek(fd: i32, offset: isize, whence: c_int) usize { + return errnoWrap(c.lseek(fd, offset, whence)); } -pub fn exit(status: i32) noreturn { - _ = arch.syscall1(SYS_exit, @bitCast(usize, isize(status))); - unreachable; +pub fn exit(code: i32) noreturn { + c.exit(code); } pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { - return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); + return errnoWrap(c.getrandom(buf, count, flags)); } pub fn kill(pid: i32, sig: i32) usize { @@ -676,15 +681,16 @@ pub fn kill(pid: i32, sig: i32) usize { } pub fn unlink(path: [*]const u8) usize { - return arch.syscall1(SYS_unlink, @ptrToInt(path)); + return errnoWrap(c.unlink(path)); } -pub fn waitpid(pid: i32, status: *i32, options: i32) usize { - return arch.syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); +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 arch.syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); + return errnoWrap(c.nanosleep(req, rem)); } pub fn setuid(uid: u32) usize { @@ -696,11 +702,11 @@ pub fn setgid(gid: u32) usize { } pub fn setreuid(ruid: u32, euid: u32) usize { - return arch.syscall2(SYS_setreuid, ruid, euid); + return errnoWrap(c.setreuid(ruid, euid)); } pub fn setregid(rgid: u32, egid: u32) usize { - return arch.syscall2(SYS_setregid, rgid, egid); + return errnoWrap(c.setregid(rgid, egid)); } const NSIG = 32; @@ -745,26 +751,16 @@ pub const sigset_t = extern struct { }; pub fn raise(sig: i32) usize { - // TODO have a chat with the freebsd folks and make sure there's no bug in - // their libc. musl-libc blocks signals in between these calls because - // if a signal handler runs and forks between the gettid and sending the - // signal, the parent will get 2 signals, one from itself and one from the child - // if the protection does not belong here, then it belongs in abort(), - // like it does in freebsd's libc. - var id: usize = undefined; - const rc = arch.syscall1(SYS_thr_self, @ptrToInt(&id)); - if (getErrno(rc) != 0) return rc; - return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig))); + 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, stat_buf: *Stat) usize { - return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); +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, From 1811e7e6c96844a8381e6a69017948cae0b8b261 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 02:42:54 -0200 Subject: [PATCH 042/218] freebsd: remove getrandom dependency from libc The system call getrandom(2) just landed on FreeBSD 12, so if we want to support some earlier version or at least FreeBSD 11, we can't depend on the system call. --- std/c/freebsd.zig | 1 - std/os/freebsd/index.zig | 4 ---- std/os/index.zig | 4 ++-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 32cd48748c..86213ee1b3 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -15,7 +15,6 @@ pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usi pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; -pub extern "c" fn getrandom(buf: [*]u8, count: usize, flags: u32) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 9191dc3219..9f9f7f9de0 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -672,10 +672,6 @@ pub fn exit(code: i32) noreturn { c.exit(code); } -pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { - return errnoWrap(c.getrandom(buf, count, flags)); -} - pub fn kill(pid: i32, sig: i32) usize { return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); } diff --git a/std/os/index.zig b/std/os/index.zig index 778ab156b0..b49b46e8e5 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -103,7 +103,7 @@ const math = std.math; /// library implementation. pub fn getRandomBytes(buf: []u8) !void { switch (builtin.os) { - Os.linux, Os.freebsd => while (true) { + 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)); @@ -116,7 +116,7 @@ pub fn getRandomBytes(buf: []u8) !void { else => return unexpectedErrorPosix(errno), } }, - Os.macosx, Os.ios => return getRandomBytesDevURandom(buf), + Os.macosx, Os.ios, Os.freebsd => return getRandomBytesDevURandom(buf), Os.windows => { // Call RtlGenRandom() instead of CryptGetRandom() on Windows // https://github.com/rust-lang-nursery/rand/issues/111 From 9900f94afe5556db048b4b147bbf75ff0e0c9974 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 16:22:20 -0200 Subject: [PATCH 043/218] freebsd: use sysctl to get the current executable path FreeBSD doesn't mount procfs as default on the base system, so we can't depend on it to get the current path, In this case, we use sysctl(3) to retrieves the system information and get the same information. - CTL_KERN: High kernel limits - KERN_PROC: Return selected information about specific running processes. - KERN_PROC_PATHNAME: The path of the process - Process ID: a process ID of -1 implies the current process. --- std/os/freebsd/index.zig | 6 ++++++ std/os/index.zig | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 9f9f7f9de0..47f4e8e267 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -9,6 +9,12 @@ 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; diff --git a/std/os/index.zig b/std/os/index.zig index b49b46e8e5..817f11493c 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -2291,7 +2291,20 @@ pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 { pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 { switch (builtin.os) { Os.linux => return readLink(out_buffer, "/proc/self/exe"), - Os.freebsd => return readLink(out_buffer, "/proc/curproc/file"), + 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.windows => { var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined; const utf16le_slice = try selfExePathW(&utf16le_buf); From e5b4748101ca40f5dc4082ce2cb46df0c8607417 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Tue, 18 Dec 2018 16:34:51 -0200 Subject: [PATCH 044/218] freebsd: initial stack trace Stack trace is partially working, with only a few symbols missing. Uses the same functions that we use in Linux to get the necessary debug info. --- std/debug/index.zig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 73c6ea7b56..2f0c55cb3d 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -264,7 +264,7 @@ pub fn writeCurrentStackTraceWindows( 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 => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color), + builtin.Os.linux, builtin.Os.freebsd => 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, } @@ -717,7 +717,7 @@ pub const OpenSelfDebugInfoError = error{ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { switch (builtin.os) { - builtin.Os.linux => return openSelfDebugInfoLinux(allocator), + builtin.Os.linux, builtin.Os.freebsd => return openSelfDebugInfoLinux(allocator), builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator), builtin.Os.windows => return openSelfDebugInfoWindows(allocator), else => return error.UnsupportedOperatingSystem, @@ -1141,8 +1141,7 @@ pub const DebugInfo = switch (builtin.os) { sect_contribs: []pdb.SectionContribEntry, modules: []Module, }, - builtin.Os.linux => DwarfInfo, - builtin.Os.freebsd => struct {}, + builtin.Os.linux, builtin.Os.freebsd => DwarfInfo, else => @compileError("Unsupported OS"), }; From 8768816d69ddf3253d2598923643f390cc18082c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Dec 2018 17:48:21 -0500 Subject: [PATCH 045/218] std.io: call the idiomatic std.mem.readInt functions I originally called the Slice variants to work around comptime code not supporting `@ptrCast`, but I fixed that in 757d0665 so now the workaround is no longer needed. --- std/io.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/io.zig b/std/io.zig index c40ededc00..428d95725d 100644 --- a/std/io.zig +++ b/std/io.zig @@ -155,32 +155,32 @@ pub fn InStream(comptime ReadError: type) type { pub fn readIntNative(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceNative(T, bytes); + return mem.readIntNative(T, &bytes); } /// Reads a foreign-endian integer pub fn readIntForeign(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceForeign(T, bytes); + return mem.readIntForeign(T, &bytes); } pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceLittle(T, bytes); + return mem.readIntLittle(T, &bytes); } pub fn readIntBig(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceBig(T, bytes); + return mem.readIntBig(T, &bytes); } pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSlice(T, bytes, endian); + return mem.readInt(T, &bytes, endian); } pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType { From 39567e8b50e9026288bb1323d84f481740bd0de7 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Thu, 20 Dec 2018 22:47:44 +0900 Subject: [PATCH 046/218] src/analyze.cpp: support alignOf(struct T) aligned member inside struct T; ref: ziglang/zig#1832 --- src/analyze.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 46686ce772..e209822132 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2686,13 +2686,22 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } size_t field_count = struct_type->data.structure.src_field_count; + bool self_resolving = false; for (size_t i = 0; i < field_count; i += 1) { TypeStructField *field = &struct_type->data.structure.fields[i]; - // If this assertion trips, look up the call stack. Probably something is - // calling type_resolve with ResolveStatusAlignmentKnown when it should only - // be resolving ResolveStatusZeroBitsKnown - assert(field->type_entry != nullptr); + // If we have no type_entry for the field, assume that we are in the + // midst of resolving this struct. We further assume that since the + // resolved alignment of the other fields of this struct is ultimately + // equal to the resolved alignment of this struct, we can safely ignore. + // + // If this struct is used down-stream in aligning a sub-struct, ignoring + // this struct in the context of a sub struct has the same effect since + // the other fields will be calculated and bubble-up. + if (nullptr == field->type_entry) { + self_resolving = true; + continue; + } if (type_is_invalid(field->type_entry)) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; @@ -2723,6 +2732,14 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } + if ( self_resolving + && field_count > 0 + ) { + // If we get here it's due to self-referencing this struct before it has been fully resolved. + // In this case, set alignment to target pointer default. + struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, + LLVMPointerType(LLVMInt8Type(), 0)); + } struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; return ErrorNone; } From fb81b1978b87be5a72328a4d9efc21561ae53cfc Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Thu, 20 Dec 2018 22:49:09 +0900 Subject: [PATCH 047/218] tests: re: 79db394; ref: ziglang/zig#1832 --- std/array_list.zig | 11 +++++ .../cases/struct_contains_slice_of_itself.zig | 42 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/std/array_list.zig b/std/array_list.zig index 3ee425fe14..ddad9c989c 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" { assert(list.len == 6); assert(list.items[0] == 1); } + +const Item = struct { + integer: i32, + sub_items: ArrayList(Item), +}; + +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) } ); + assert(root.sub_items.items[0].integer == 42); +} diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig index 07987ae32b..aa3075312c 100644 --- a/test/cases/struct_contains_slice_of_itself.zig +++ b/test/cases/struct_contains_slice_of_itself.zig @@ -5,6 +5,11 @@ const Node = struct { children: []Node, }; +const NodeAligned = struct { + payload: i32, + children: []align(@alignOf(NodeAligned)) NodeAligned, +}; + test "struct contains slice of itself" { var other_nodes = []Node{ Node{ @@ -41,3 +46,40 @@ test "struct contains slice of itself" { assert(root.children[2].children[0].payload == 31); assert(root.children[2].children[1].payload == 32); } + +test "struct contains aligned slice of itself" { + var other_nodes = []NodeAligned{ + NodeAligned{ + .payload = 31, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 32, + .children = []NodeAligned{}, + }, + }; + var nodes = []NodeAligned{ + NodeAligned{ + .payload = 1, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 2, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 3, + .children = other_nodes[0..], + }, + }; + const root = NodeAligned{ + .payload = 1234, + .children = nodes[0..], + }; + assert(root.payload == 1234); + assert(root.children[0].payload == 1); + assert(root.children[1].payload == 2); + assert(root.children[2].payload == 3); + assert(root.children[2].children[0].payload == 31); + assert(root.children[2].children[1].payload == 32); +} From 0f54194e6ab2b0cbdc798b84cc4213a07ed1d0c1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 12:36:15 -0500 Subject: [PATCH 048/218] fixups --- src/analyze.cpp | 70 ++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index e209822132..9c24f3cc8d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2681,48 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { assert(decl_node->type == NodeTypeContainerDecl); assert(struct_type->di_type); + size_t field_count = struct_type->data.structure.src_field_count; if (struct_type->data.structure.layout == ContainerLayoutPacked) { struct_type->data.structure.abi_alignment = 1; - } - - size_t field_count = struct_type->data.structure.src_field_count; - bool self_resolving = false; - for (size_t i = 0; i < field_count; i += 1) { + for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = &struct_type->data.structure.fields[i]; + if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } + } + } else for (size_t i = 0; i < field_count; i += 1) { TypeStructField *field = &struct_type->data.structure.fields[i]; + uint32_t this_field_align; - // If we have no type_entry for the field, assume that we are in the - // midst of resolving this struct. We further assume that since the - // resolved alignment of the other fields of this struct is ultimately - // equal to the resolved alignment of this struct, we can safely ignore. - // - // If this struct is used down-stream in aligning a sub-struct, ignoring - // this struct in the context of a sub struct has the same effect since - // the other fields will be calculated and bubble-up. - if (nullptr == field->type_entry) { - self_resolving = true; - continue; - } + // TODO If we have no type_entry for the field, we've already failed to + // compile the program correctly. This stage1 compiler needs a deeper + // reworking to make this correct, or we can ignore the problem + // and make sure it is fixed in stage2. This workaround is for when + // there is a false positive of a dependency loop, of alignment depending + // on itself. When this false positive happens we assume a pointer-aligned + // field, which is usually fine but could be incorrectly over-aligned or + // even under-aligned. See https://github.com/ziglang/zig/issues/1512 + if (field->type_entry == nullptr) { + this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); + } else { + if (type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } - if (type_is_invalid(field->type_entry)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - break; - } + if (!type_has_bits(field->type_entry)) + continue; - if (!type_has_bits(field->type_entry)) - continue; - - // alignment of structs is the alignment of the most-aligned field - if (struct_type->data.structure.layout != ContainerLayoutPacked) { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } - uint32_t this_field_align = get_abi_alignment(g, field->type_entry); + this_field_align = get_abi_alignment(g, field->type_entry); assert(this_field_align != 0); - if (this_field_align > struct_type->data.structure.abi_alignment) { - struct_type->data.structure.abi_alignment = this_field_align; - } + } + // alignment of structs is the alignment of the most-aligned field + if (this_field_align > struct_type->data.structure.abi_alignment) { + struct_type->data.structure.abi_alignment = this_field_align; } } @@ -2732,14 +2734,6 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - if ( self_resolving - && field_count > 0 - ) { - // If we get here it's due to self-referencing this struct before it has been fully resolved. - // In this case, set alignment to target pointer default. - struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, - LLVMPointerType(LLVMInt8Type(), 0)); - } struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; return ErrorNone; } From 48406009889c0e77052b57bc0220a332d3ea5cbd Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Wed, 19 Dec 2018 22:34:51 -0200 Subject: [PATCH 049/218] ci: add sr.ht build manifest for FreeBSD --- .builds/freebsd.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .builds/freebsd.yml diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml new file mode 100644 index 0000000000..e293561c23 --- /dev/null +++ b/.builds/freebsd.yml @@ -0,0 +1,15 @@ +arch: x86_64 +image: freebsd +packages: + - cmake + - llvm70 +sources: + - https://github.com/ziglang/zig.git +tasks: + - build: | + cd zig && mkdir build && cd build + cmake .. + make && make install + - test: | + cd zig && cd build + ./bin/zig build --build-file ../build.zig test From 2a776ed8a8ff9220e316cb91fbfb49f23edee0d1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 13:05:34 -0500 Subject: [PATCH 050/218] ci: only run the debug behavior tests for FreeBSD --- .builds/freebsd.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index e293561c23..80b50841a9 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -8,8 +8,14 @@ sources: tasks: - build: | cd zig && mkdir build && cd build - cmake .. - make && make install + cmake .. -DCMAKE_BUILD_TYPE=Release + make -j$(sysctl -n hw.ncpu) install - test: | - cd zig && cd build - ./bin/zig build --build-file ../build.zig test + cd zig/build + bin/zig test ../test/behavior.zig + # TODO enable all tests + #bin/zig build --build-file ../build.zig test + # TODO integrate with the download page updater and make a + # static build available to download for FreeBSD. + # This will require setting up a cache of LLVM/Clang built + # statically. From f35ba34a884eb8253c2ddd584605191e1b977595 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Thu, 20 Dec 2018 11:51:37 -0600 Subject: [PATCH 051/218] Removed allocator from Linux version DynLib. Added dynamic_library.zig to std test list. --- std/dynamic_library.zig | 4 +--- std/index.zig | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 49f217bc8e..4d19951318 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -19,7 +19,6 @@ pub const DynLib = switch (builtin.os) { }; pub const LinuxDynLib = struct { - allocator: *mem.Allocator, elf_lib: ElfLib, fd: i32, map_addr: usize, @@ -27,7 +26,7 @@ pub const LinuxDynLib = struct { /// Trusts the file pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib { - const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC); + const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC); errdefer std.os.close(fd); const size = @intCast(usize, (try std.os.posixFStat(fd)).size); @@ -45,7 +44,6 @@ pub const LinuxDynLib = struct { const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size]; return DynLib{ - .allocator = allocator, .elf_lib = try ElfLib.init(bytes), .fd = fd, .map_addr = addr, diff --git a/std/index.zig b/std/index.zig index 55ad016bb1..33eec14b0e 100644 --- a/std/index.zig +++ b/std/index.zig @@ -57,7 +57,8 @@ test "std" { _ = @import("mutex.zig"); _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); - + + _ = @import("dynamic_library.zig"); _ = @import("base64.zig"); _ = @import("build.zig"); _ = @import("c/index.zig"); From fa6c7c130308534af6da93ce3f46520e0bb07ba4 Mon Sep 17 00:00:00 2001 From: myfreeweb Date: Thu, 20 Dec 2018 23:01:49 +0300 Subject: [PATCH 052/218] Use Ninja in .builds/freebsd.yml It's faster and doesn't require manually getting the number of CPUs --- .builds/freebsd.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 80b50841a9..db1ddb337a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -2,14 +2,15 @@ arch: x86_64 image: freebsd packages: - cmake + - ninja - llvm70 sources: - https://github.com/ziglang/zig.git tasks: - build: | cd zig && mkdir build && cd build - cmake .. -DCMAKE_BUILD_TYPE=Release - make -j$(sysctl -n hw.ncpu) install + cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release + ninja install - test: | cd zig/build bin/zig test ../test/behavior.zig From 054c7ab18a8c9527414164bf68aa3564c29e8931 Mon Sep 17 00:00:00 2001 From: Greg V Date: Thu, 20 Dec 2018 23:54:09 +0300 Subject: [PATCH 053/218] Fix stat/timespec definitions for FreeBSD --- std/c/freebsd.zig | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 86213ee1b3..72969fa826 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -50,18 +50,23 @@ pub const Stat = extern struct { nlink: usize, mode: u32, + __pad0: u16, uid: u32, gid: u32, - __pad0: u32, + __pad1: u32, rdev: u64, - size: i64, - blksize: isize, - blocks: i64, atim: timespec, mtim: timespec, ctim: timespec, - __unused: [3]isize, + birthtim: timespec, + + size: i64, + blocks: i64, + blksize: isize, + flags: u32, + gen: u64, + __spare: [10]u64, }; pub const timespec = extern struct { @@ -72,7 +77,7 @@ pub const timespec = extern struct { pub const dirent = extern struct { d_fileno: usize, d_off: i64, - d_reclen: u64, + d_reclen: u16, d_type: u8, d_pad0: u8, d_namlen: u16, From 76efc462e7ea90be02fd28254f8c452ba994ea8a Mon Sep 17 00:00:00 2001 From: Greg V Date: Thu, 20 Dec 2018 23:55:44 +0300 Subject: [PATCH 054/218] Add preadv/pwritev on FreeBSD --- std/c/freebsd.zig | 2 ++ std/os/freebsd/index.zig | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 72969fa826..f30d57da3b 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -15,6 +15,8 @@ pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usi pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; +pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; +pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 47f4e8e267..1e08afe26d 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -626,7 +626,7 @@ pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize { } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize { - return arch.syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); + return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset)); } pub fn pipe(fd: *[2]i32) usize { @@ -647,7 +647,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize { } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); + 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 { From 46a0f60e4c0c91f840982cb98066d60301624548 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Thu, 20 Dec 2018 20:57:58 -0200 Subject: [PATCH 055/218] freebsd: use realpath() to resolve symbolic links --- std/os/path.zig | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/std/os/path.zig b/std/os/path.zig index af767b0dca..ff70bc039e 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1161,7 +1161,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const pathname_w = try windows_util.cStrToPrefixedFileW(pathname); return realW(out_buffer, pathname_w); }, - Os.macosx, Os.ios => { + Os.freebsd, Os.macosx, Os.ios => { // TODO instead of calling the libc function here, port the implementation to Zig const err = posix.getErrno(posix.realpath(pathname, out_buffer)); switch (err) { @@ -1188,15 +1188,6 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro return os.readLinkC(out_buffer, proc_path.ptr); }, - Os.freebsd => { // XXX requires fdescfs - const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); - defer os.close(fd); - - var buf: ["/dev/fd/-2147483648\x00".len]u8 = undefined; - const proc_path = fmt.bufPrint(buf[0..], "/dev/fd/{}\x00", fd) catch unreachable; - - return os.readLinkC(out_buffer, proc_path.ptr); - }, else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)), } } From a6f33e3dc56eab57ee148c2ec7592540470d582c Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Thu, 20 Dec 2018 21:05:31 -0200 Subject: [PATCH 056/218] freebsd: add realpath to freebsd/index.zig --- std/os/freebsd/index.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 1e08afe26d..f1533ec098 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -580,6 +580,10 @@ 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; } From c156d51d555441b41f512d854529ea28db95dd50 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Thu, 20 Dec 2018 21:44:18 -0200 Subject: [PATCH 057/218] freebsd: remove system linker hack --- build.zig | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.zig b/build.zig index 2a51203ff7..16185eebf4 100644 --- a/build.zig +++ b/build.zig @@ -299,9 +299,6 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { } else if (exe.target.isFreeBSD()) { try addCxxKnownPath(b, ctx, exe, "libc++.a", null); exe.linkSystemLibrary("pthread"); - // TODO LLD cannot perform this link. - // See https://github.com/ziglang/zig/issues/1535 - exe.enableSystemLinkerHack(); } else if (exe.target.isDarwin()) { if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { From 56fedbb52423eba6d2088a1e2c8b94e0c4eb85ac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 19:56:24 -0500 Subject: [PATCH 058/218] translate-c: --verbose-cimport prints clang command --- src/translate_c.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 10f2124eb6..f6bc9cd683 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4776,6 +4776,14 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const clang_argv.append(target_file); + if (codegen->verbose_cimport) { + fprintf(stderr, "clang"); + for (size_t i = 0; i < clang_argv.length; i += 1) { + fprintf(stderr, " %s", clang_argv.at(i)); + } + fprintf(stderr, "\n"); + } + // to make the [start...end] argument work clang_argv.append(nullptr); From c26f543970771acba5484553e2c10ec90b3c39eb Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 21 Dec 2018 15:04:55 -0200 Subject: [PATCH 059/218] freebsd: fix Stat mode type --- std/c/freebsd.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index f30d57da3b..9aa1859988 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -51,7 +51,7 @@ pub const Stat = extern struct { ino: u64, nlink: usize, - mode: u32, + mode: u16, __pad0: u16, uid: u32, gid: u32, From 0eba5b6744c51892348a7b71726891189b0af7d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Dec 2018 19:50:21 -0500 Subject: [PATCH 060/218] I observed open() return EBUSY on linux when trying to open for writing a tty fd that is already opened with screen --- std/os/index.zig | 5 +++++ std/os/path.zig | 1 + 2 files changed, 6 insertions(+) diff --git a/std/os/index.zig b/std/os/index.zig index be82ad4716..b19679c969 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -459,6 +459,7 @@ pub const PosixOpenError = error{ NoSpaceLeft, NotDir, PathAlreadyExists, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, @@ -497,6 +498,7 @@ pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 { posix.ENOTDIR => return PosixOpenError.NotDir, posix.EPERM => return PosixOpenError.AccessDenied, posix.EEXIST => return PosixOpenError.PathAlreadyExists, + posix.EBUSY => return PosixOpenError.DeviceBusy, else => return unexpectedErrorPosix(err), } } @@ -1402,6 +1404,7 @@ const DeleteTreeError = error{ FileSystem, FileBusy, DirNotEmpty, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -1463,6 +1466,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! error.Unexpected, error.InvalidUtf8, error.BadPathName, + error.DeviceBusy, => return err, }; defer dir.close(); @@ -1545,6 +1549,7 @@ pub const Dir = struct { OutOfMemory, InvalidUtf8, BadPathName, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, diff --git a/std/os/path.zig b/std/os/path.zig index af767b0dca..e61a0f84bc 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1093,6 +1093,7 @@ pub const RealError = error{ NoSpaceLeft, FileSystem, BadPathName, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, From f301474531fc640729aaa52d66209317c76367c8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Dec 2018 23:01:21 -0500 Subject: [PATCH 061/218] self-hosted: add DeviceBusy as a BuildError --- src-self-hosted/compilation.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 0594cbd749..c00c7c1d41 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -300,6 +300,7 @@ pub const Compilation = struct { UserResourceLimitReached, InvalidUtf8, BadPathName, + DeviceBusy, }; pub const Event = union(enum) { From 218a4d4b30f320797121ad9900d48743da77a1b3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 22 Dec 2018 23:06:30 -0500 Subject: [PATCH 062/218] comptime: ability to @ptrCast to an extern struct and read fields --- src/ir.cpp | 64 ++++++++++++++++++++++++++++++++---------- test/cases/ptrcast.zig | 19 +++++++++++++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 028582f87f..83960f2eee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -159,7 +159,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); @@ -13725,7 +13725,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, Buf buf = BUF_INIT; buf_resize(&buf, src_size); buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } @@ -13759,7 +13760,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } case ConstPtrSpecialBaseStruct: @@ -20077,7 +20079,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { + Error err; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: @@ -20094,30 +20097,60 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdPromise: zig_unreachable(); case ZigTypeIdVoid: - return; + return ErrorNone; case ZigTypeIdBool: val->data.x_bool = (buf[0] != 0); - return; + return ErrorNone; case ZigTypeIdInt: bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian, val->type->data.integral.is_signed); - return; + ira->codegen->is_big_endian, val->type->data.integral.is_signed); + return ErrorNone; case ZigTypeIdFloat: - float_read_ieee597(val, buf, codegen->is_big_endian); - return; + float_read_ieee597(val, buf, ira->codegen->is_big_endian); + return ErrorNone; case ZigTypeIdPointer: { val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; BigInt bn; - bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, - codegen->is_big_endian, false); + bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count, + ira->codegen->is_big_endian, false); val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); - return; + return ErrorNone; } case ZigTypeIdArray: zig_panic("TODO buf_read_value_bytes array type"); case ZigTypeIdStruct: - zig_panic("TODO buf_read_value_bytes struct type"); + switch (val->type->data.structure.layout) { + case ContainerLayoutAuto: { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", + buf_ptr(&val->type->name))); + add_error_note(ira->codegen, msg, val->type->data.structure.decl_node, + buf_sprintf("declared here")); + return ErrorSemanticAnalyzeFail; + } + case ContainerLayoutExtern: { + size_t src_field_count = val->type->data.structure.src_field_count; + val->data.x_struct.fields = create_const_vals(src_field_count); + for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { + ConstExprValue *field_val = &val->data.x_struct.fields[field_i]; + field_val->special = ConstValSpecialStatic; + TypeStructField *type_field = &val->type->data.structure.fields[field_i]; + field_val->type = type_field->type_entry; + if (type_field->gen_index == SIZE_MAX) + continue; + size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref, + type_field->gen_index); + uint8_t *new_buf = buf + offset; + if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val))) + return err; + } + return ErrorNone; + } + case ContainerLayoutPacked: + zig_panic("TODO buf_read_value_bytes packed struct"); + } + zig_unreachable(); case ZigTypeIdOptional: zig_panic("TODO buf_read_value_bytes maybe type"); case ZigTypeIdErrorUnion: @@ -20220,7 +20253,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - buf_read_value_bytes(ira->codegen, buf, &result->value); + if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value))) + return ira->codegen->invalid_instruction; return result; } diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig index 071087c5c4..6f0e6e5946 100644 --- a/test/cases/ptrcast.zig +++ b/test/cases/ptrcast.zig @@ -15,3 +15,22 @@ fn testReinterpretBytesAsInteger() void { }; assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); } + +test "reinterpret bytes of an array into an extern struct" { + testReinterpretBytesAsExternStruct(); + comptime testReinterpretBytesAsExternStruct(); +} + +fn testReinterpretBytesAsExternStruct() void { + var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; + + const S = extern struct { + a: u8, + b: u16, + c: u8, + }; + + var ptr = @ptrCast(*const S, &bytes); + var val = ptr.c; + assertOrPanic(val == 5); +} From 45081c1e9cc28757cb563c77553631f7a92b29d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 23 Dec 2018 13:56:49 -0500 Subject: [PATCH 063/218] hello world example can use `const` instead of `var` --- doc/langref.html.in | 2 +- example/hello_world/hello.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f41eb2dec1..2a2b4003fb 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -165,7 +165,7 @@ const std = @import("std"); pub fn main() !void { // If this program is run without stdout attached, exit with an error. - var stdout_file = try std.io.getStdOut(); + const stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit // with an error. try stdout_file.write("Hello, world!\n"); diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig index 8e65e06a96..cb7d5ef157 100644 --- a/example/hello_world/hello.zig +++ b/example/hello_world/hello.zig @@ -2,7 +2,7 @@ const std = @import("std"); pub fn main() !void { // If this program is run without stdout attached, exit with an error. - var stdout_file = try std.io.getStdOut(); + const stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit // with an error. try stdout_file.write("Hello, world!\n"); From 280187031a68c577e84c72add037271153d27c62 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 23 Dec 2018 18:03:22 -0500 Subject: [PATCH 064/218] tests: make type info tests not depend on builtin.Os enum --- test/cases/type_info.zig | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig index 6f99268c08..cec532d5d3 100644 --- a/test/cases/type_info.zig +++ b/test/cases/type_info.zig @@ -144,15 +144,20 @@ test "type info: enum info" { } fn testEnum() void { - const Os = @import("builtin").Os; + const Os = enum { + Windows, + Macos, + Linux, + FreeBSD, + }; const os_info = @typeInfo(Os); assert(TypeId(os_info) == TypeId.Enum); assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assert(os_info.Enum.fields.len == 32); - assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas")); - assert(os_info.Enum.fields[10].value == 10); - assert(os_info.Enum.tag_type == u5); + assert(os_info.Enum.fields.len == 4); + assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); + assert(os_info.Enum.fields[3].value == 3); + assert(os_info.Enum.tag_type == u2); assert(os_info.Enum.defs.len == 0); } From 682815f6e9df8fa7ec25f0b327b4eab7c3d52f2a Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Sun, 23 Dec 2018 23:30:31 -0200 Subject: [PATCH 065/218] freebsd: remove syscall and use libc Use libc interface for: - getdents - kill - openat - setgid - setuid --- std/c/freebsd.zig | 5 +++++ std/os/freebsd/index.zig | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 9aa1859988..eae5516db3 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -14,9 +14,14 @@ pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlen pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; +pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; +pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int; +pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; +pub extern "c" fn setuid(uid: c_uint) c_int; +pub extern "c" fn kill(pid: c_int, sig: c_int) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index f1533ec098..ebea64fdf6 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -573,7 +573,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { - return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); + return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count))); } pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize { @@ -667,7 +667,7 @@ pub fn create(path: [*]const u8, perm: usize) usize { } pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { - return arch.syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); + return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode)); } pub fn close(fd: i32) usize { @@ -683,7 +683,7 @@ pub fn exit(code: i32) noreturn { } pub fn kill(pid: i32, sig: i32) usize { - return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); + return errnoWrap(c.kill(pid, sig)); } pub fn unlink(path: [*]const u8) usize { @@ -700,11 +700,11 @@ pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { } pub fn setuid(uid: u32) usize { - return arch.syscall1(SYS_setuid, uid); + return errnoWrap(c.setuid(uid)); } pub fn setgid(gid: u32) usize { - return arch.syscall1(SYS_setgid, gid); + return errnoWrap(c.setgid(gid)); } pub fn setreuid(ruid: u32, euid: u32) usize { From 39d32ee40a53deb99a3683fed4574adceca95afe Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Sun, 23 Dec 2018 22:21:32 -0500 Subject: [PATCH 066/218] Altered SUBSYSTEM option handling when linking in msvc mode; Added preliminary UEFI support. --- CMakeLists.txt | 1 + src-self-hosted/target.zig | 2 +- src/all_types.hpp | 3 +- src/analyze.cpp | 12 +++---- src/codegen.cpp | 11 ++---- src/codegen.hpp | 1 - src/ir.cpp | 8 ++++- src/link.cpp | 74 ++++++++++++++++++++++++++++---------- src/main.cpp | 34 +++++++++++++++--- src/target.cpp | 10 ++++-- src/target.hpp | 2 ++ src/translate_c.cpp | 6 ++-- src/zig_llvm.cpp | 9 ++++- src/zig_llvm.h | 18 ++++++++-- std/debug/index.zig | 2 +- std/os/index.zig | 7 ++++ std/os/uefi/index.zig | 0 std/special/panic.zig | 2 +- 18 files changed, 152 insertions(+), 50 deletions(-) create mode 100644 std/os/uefi/index.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b64bcca81..7b31f96562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -590,6 +590,7 @@ set(ZIG_STD_FILES "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" + "os/uefi/index.zig" "os/windows/advapi32.zig" "os/windows/error.zig" "os/windows/index.zig" diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 218353c9d7..36381b820d 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -520,7 +520,7 @@ pub const Target = union(enum) { => return 64, }, - builtin.Os.windows => switch (id) { + builtin.Os.windows, builtin.Os.uefi => switch (id) { CInt.Id.Short, CInt.Id.UShort, => return 16, diff --git a/src/all_types.hpp b/src/all_types.hpp index 11304e536d..26e9edbab4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1754,8 +1754,7 @@ struct CodeGen { bool strip_debug_symbols; bool is_test_build; bool is_native_target; - bool windows_subsystem_windows; - bool windows_subsystem_console; + ZigLLVM_MSVCSubsystemType msvc_subsystem; bool linker_rdynamic; bool no_rosegment_workaround; bool each_lib_rpath; diff --git a/src/analyze.cpp b/src/analyze.cpp index 9c24f3cc8d..48d473fb37 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3203,24 +3203,25 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi if (ccc) { if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { g->have_c_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; } else if (buf_eql_str(symbol_name, "WinMain") && g->zig_target.os == OsWindows) { g->have_winmain = true; - g->windows_subsystem_windows = true; - g->windows_subsystem_console = false; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_winmain_crt_startup = true; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_dllmain_crt_startup = true; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } } + FnExport *fn_export = fn_table_entry->export_list.add_one(); memset(fn_export, 0, sizeof(FnExport)); buf_init_from_buf(&fn_export->name, symbol_name); @@ -4376,8 +4377,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } diff --git a/src/codegen.cpp b/src/codegen.cpp index e37703d5f0..b76bbfb492 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -291,11 +291,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) { g->darwin_frameworks.append(buf_create_from_str(framework)); } -void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole) { - g->windows_subsystem_windows = mwindows; - g->windows_subsystem_console = mconsole; -} - void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) { g->mmacosx_version_min = mmacosx_version_min; } @@ -7273,7 +7268,7 @@ static void init(CodeGen *g) { // LLVM creates invalid binaries on Windows sometimes. // See https://github.com/ziglang/zig/issues/508 // As a workaround we do not use target native features on Windows. - if (g->zig_target.os == OsWindows) { + if (g->zig_target.os == OsWindows || g->zig_target.os == OsUefi) { target_specific_cpu_args = ""; target_specific_features = ""; } else { @@ -7519,6 +7514,7 @@ static void gen_root_source(CodeGen *g) { report_errors_and_maybe_exit(g); if (!g->is_test_build && g->zig_target.os != OsFreestanding && + g->zig_target.os != OsZen && g->zig_target.os != OsUefi && !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { @@ -8079,8 +8075,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); cache_bool(ch, g->is_native_target); - cache_bool(ch, g->windows_subsystem_windows); - cache_bool(ch, g->windows_subsystem_console); + cache_int(ch, g->msvc_subsystem); cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); cache_bool(ch, g->each_lib_rpath); diff --git a/src/codegen.hpp b/src/codegen.hpp index 1d39e4bf5e..6f1cdfb677 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -33,7 +33,6 @@ void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir); void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir); void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir); void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); -void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole); void codegen_add_lib_dir(CodeGen *codegen, const char *dir); void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib); LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib); diff --git a/src/ir.cpp b/src/ir.cpp index 83960f2eee..a1432c7b11 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17872,7 +17872,13 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct if (type_is_invalid(cimport_result->value.type)) return ira->codegen->invalid_instruction; - find_libc_include_path(ira->codegen); + if (ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_APPLICATION && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_ROM && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_RUNTIME_DRIVER) { + + find_libc_include_path(ira->codegen); + } ImportTableEntry *child_import = allocate(1); child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import); diff --git a/src/link.cpp b/src/link.cpp index 188f976a86..52ca2f2cd9 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -455,7 +455,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append("-NOLOGO"); - if (!g->strip_debug_symbols) { + if (!g->strip_debug_symbols && g->zig_target.os != Os::OsUefi) { lj->args.append("-DEBUG"); } @@ -466,11 +466,6 @@ static void construct_linker_job_coff(LinkJob *lj) { coff_append_machine_arg(g, &lj->args); - if (g->windows_subsystem_windows) { - lj->args.append("/SUBSYSTEM:windows"); - } else if (g->windows_subsystem_console) { - lj->args.append("/SUBSYSTEM:console"); - } // The commented out stuff is from when we linked with MinGW // Now that we're linking with LLD it remains to be determined // how to handle --target-environ gnu @@ -499,18 +494,47 @@ static void construct_linker_job_coff(LinkJob *lj) { // } //} - lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); - if (g->libc_link_lib != nullptr) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir)))); - - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); - if (g->libc_static_lib_dir != nullptr) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); - } + // These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning + // up a bit for building the COFF linker args: + // /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" + // /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" + + // Sorry for the goto(s) :) + switch (g->msvc_subsystem) { + case ZigLLVM_MSVC_CONSOLE: + lj->args.append("/SUBSYSTEM:console"); + goto building_nt; + case ZigLLVM_MSVC_EFI_APPLICATION: + lj->args.append("/SUBSYSTEM:efi_application"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER: + lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_ROM: + lj->args.append("/SUBSYSTEM:efi_rom"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_RUNTIME_DRIVER: + lj->args.append("/SUBSYSTEM:efi_runtime_driver"); + goto building_uefi; + case ZigLLVM_MSVC_NATIVE: + lj->args.append("/SUBSYSTEM:native"); + goto building_nt; + case ZigLLVM_MSVC_POSIX: + lj->args.append("/SUBSYSTEM:posix"); + goto building_nt; + case ZigLLVM_MSVC_WINDOWS: + lj->args.append("/SUBSYSTEM:windows"); + goto building_nt; + case ZigLLVM_MSVC_NONE: + goto continuing_build; } +building_uefi: + lj->args.append("/BASE:\"0\" /ENTRY:\"EfiMain\" /OPT:REF /SAFESEH:NO /MERGE:\".rdata=.data\" /ALIGN:32 /NODEFAULTLIB /SECTION:\".xdata,D\""); + goto continuing_build; + +building_nt: if (lj->link_in_crt) { const char *lib_str = g->is_static ? "lib" : ""; const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; @@ -547,16 +571,30 @@ static void construct_linker_job_coff(LinkJob *lj) { // msvcrt depends on kernel32 lj->args.append("kernel32.lib"); } else { - lj->args.append("-NODEFAULTLIB"); + lj->args.append("/NODEFAULTLIB"); if (!is_library) { if (g->have_winmain) { - lj->args.append("-ENTRY:WinMain"); + lj->args.append("/ENTRY:WinMain"); } else { - lj->args.append("-ENTRY:WinMainCRTStartup"); + lj->args.append("/ENTRY:WinMainCRTStartup"); } } } +continuing_build: + + lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); + + if (g->libc_link_lib != nullptr) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir)))); + + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); + if (g->libc_static_lib_dir != nullptr) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); + } + } + if (is_library && !g->is_static) { lj->args.append("-DLL"); } diff --git a/src/main.cpp b/src/main.cpp index 078dfb25f9..469ec448e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,9 +90,7 @@ static int print_full_usage(const char *arg0) { " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" " --no-rosegment compromise security to workaround valgrind bug\n" - " -mconsole (windows) --subsystem console to the linker\n" - " -mwindows (windows) --subsystem windows to the linker\n" - " -framework [name] (darwin) link against framework\n" + " --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM: to the linker\n" " -framework [name] (darwin) link against framework\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" " --ver-major [ver] dynamic library semver major version\n" @@ -395,6 +393,7 @@ int main(int argc, char **argv) { int runtime_args_start = -1; bool no_rosegment_workaround = false; bool system_linker_hack = false; + ZigLLVM_MSVCSubsystemType msvc_subsystem_type = ZigLLVM_MSVC_NONE; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -540,6 +539,32 @@ int main(int argc, char **argv) { verbose_llvm_ir = true; } else if (strcmp(arg, "--verbose-cimport") == 0) { verbose_cimport = true; + } else if (strcmp(arg, "--msvc-subsystem") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "Expected 1 argument after --msvc-subsystem\n"); + return print_error_usage(arg0); + } + i += 1; + if (stricmp(argv[i], "CONSOLE") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_CONSOLE; + } else if (stricmp(argv[i], "WINDOWS") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_WINDOWS; + } else if (stricmp(argv[i], "POSIX") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_POSIX; + } else if (stricmp(argv[i], "NATIVE") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_NATIVE; + } else if (stricmp(argv[i], "EFI_APPLICATION") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_APPLICATION; + } else if (stricmp(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER; + } else if (stricmp(argv[i], "EFI_ROM") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_ROM; + } else if (stricmp(argv[i], "EFI_RUNTIME_DRIVER") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_RUNTIME_DRIVER; + } else { + fprintf(stderr, "Unknown format %s for --msvc-subsystem argument\n", argv[i]); + return EXIT_FAILURE; + } } else if (strcmp(arg, "-mwindows") == 0) { mwindows = true; } else if (strcmp(arg, "-mconsole") == 0) { @@ -849,6 +874,8 @@ int main(int argc, char **argv) { buf_out_name = buf_create_from_str("run"); } CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); + g->msvc_subsystem = msvc_subsystem_type; + if (disable_pic) { if (out_type != OutTypeLib || !is_static) { fprintf(stderr, "--disable-pic only applies to static libraries"); @@ -909,7 +936,6 @@ int main(int argc, char **argv) { codegen_add_rpath(g, rpath_list.at(i)); } - codegen_set_windows_subsystem(g, mwindows, mconsole); codegen_set_rdynamic(g, rdynamic); g->no_rosegment_workaround = no_rosegment_workaround; if (mmacosx_version_min && mios_version_min) { diff --git a/src/target.cpp b/src/target.cpp index 5a4b5252f1..6992f86cac 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -174,6 +174,7 @@ static const Os os_list[] = { OsContiki, OsAMDPAL, OsZen, + OsUefi, }; // Coordinate with zig_llvm.h @@ -315,6 +316,8 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) { return ZigLLVM_Contiki; case OsAMDPAL: return ZigLLVM_AMDPAL; + case OsUefi: + return ZigLLVM_Uefi; } zig_unreachable(); } @@ -756,6 +759,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case CIntTypeCount: zig_unreachable(); } + case OsUefi: case OsWindows: switch (id) { case CIntTypeShort: @@ -803,7 +807,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { } const char *target_o_file_ext(ZigTarget *target) { - if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows) { + if (target->env_type == ZigLLVM_MSVC || (target->os == OsWindows || target->os == OsUefi)) { return ".obj"; } else { return ".o"; @@ -821,13 +825,15 @@ const char *target_llvm_ir_file_ext(ZigTarget *target) { const char *target_exe_file_ext(ZigTarget *target) { if (target->os == OsWindows) { return ".exe"; + } else if (target->os == OsUefi) { + return ".efi"; } else { return ""; } } const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) { - if (target->os == OsWindows) { + if (target->os == OsWindows || target->os == OsUefi) { if (is_static) { return ".lib"; } else { diff --git a/src/target.hpp b/src/target.hpp index 04652179d2..62cc20711a 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -51,6 +51,7 @@ enum Os { OsContiki, OsAMDPAL, OsZen, + OsUefi, }; struct ZigTarget { @@ -59,6 +60,7 @@ struct ZigTarget { Os os; ZigLLVM_EnvironmentType env_type; ZigLLVM_ObjectFormatType oformat; + ZigLLVM_MSVCSubsystemType msvc_subsystem = ZigLLVM_MSVC_NONE; }; enum CIntType { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index f6bc9cd683..0e56e29810 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4749,8 +4749,10 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const clang_argv.append("-isystem"); clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); - clang_argv.append("-isystem"); - clang_argv.append(buf_ptr(codegen->libc_include_dir)); + if (codegen->libc_include_dir) { + clang_argv.append("-isystem"); + clang_argv.append(buf_ptr(codegen->libc_include_dir)); + } // windows c runtime requires -D_DEBUG if using debug libraries if (codegen->build_mode == BuildModeDebug) { diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index bda8fa0adc..e12ece919e 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -690,7 +690,14 @@ const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor) { } const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os) { - return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); + switch (os) { + case ZigLLVM_Zen: + return "unknown"; + case ZigLLVM_Uefi: + return "windows"; + default: + return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); + } } const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 551a4a7448..bb7cb5c5ff 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -357,8 +358,8 @@ enum ZigLLVM_OSType { ZigLLVM_Mesa3D, ZigLLVM_Contiki, ZigLLVM_AMDPAL, // AMD PAL Runtime - - ZigLLVM_LastOSType = ZigLLVM_AMDPAL + ZigLLVM_Uefi, + ZigLLVM_LastOSType = ZigLLVM_Uefi }; // Synchronize with target.cpp::environ_list @@ -397,6 +398,19 @@ enum ZigLLVM_ObjectFormatType { ZigLLVM_Wasm, }; +// For MSVC-supported subsystems +enum ZigLLVM_MSVCSubsystemType { + ZigLLVM_MSVC_NONE, + ZigLLVM_MSVC_CONSOLE, + ZigLLVM_MSVC_WINDOWS, + ZigLLVM_MSVC_POSIX, + ZigLLVM_MSVC_NATIVE, + ZigLLVM_MSVC_EFI_APPLICATION, + ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER, + ZigLLVM_MSVC_EFI_ROM, + ZigLLVM_MSVC_EFI_RUNTIME_DRIVER, +}; + ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch); ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); diff --git a/std/debug/index.zig b/std/debug/index.zig index 73c6ea7b56..93d6a60a03 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1135,7 +1135,7 @@ pub const DebugInfo = switch (builtin.os) { return self.ofiles.allocator; } }, - builtin.Os.windows => struct { + builtin.Os.uefi, builtin.Os.windows => struct { pdb: pdb.Pdb, coff: *coff.Coff, sect_contribs: []pdb.SectionContribEntry, diff --git a/std/os/index.zig b/std/os/index.zig index b19679c969..ce65667157 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -18,6 +18,7 @@ test "std.os" { _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); + _ = @import("uefi/index.zig"); _ = @import("get_app_data_dir.zig"); } @@ -26,6 +27,8 @@ pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); pub const freebsd = @import("freebsd/index.zig"); pub const zen = @import("zen.zig"); +pub const uefi = @import("uefi/index.zig"); + pub const posix = switch (builtin.os) { Os.linux => linux, Os.macosx, Os.ios => darwin, @@ -33,6 +36,7 @@ pub const posix = switch (builtin.os) { Os.zen => zen, else => @compileError("Unsupported OS"), }; + pub const net = @import("net.zig"); pub const ChildProcess = @import("child_process.zig").ChildProcess; @@ -187,6 +191,9 @@ pub fn abort() noreturn { } windows.ExitProcess(3); }, + Os.uefi => { + while (true) {} + }, else => @compileError("Unsupported OS"), } } diff --git a/std/os/uefi/index.zig b/std/os/uefi/index.zig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/std/special/panic.zig b/std/special/panic.zig index ca1caea73c..fe1e020604 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -10,7 +10,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn @setCold(true); switch (builtin.os) { // TODO: fix panic in zen. - builtin.Os.freestanding, builtin.Os.zen => { + builtin.Os.freestanding, builtin.Os.zen, builtin.Os.uefi => { while (true) {} }, else => { From fdea12b2d9deaea6a90c7b1451df425e84b98099 Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Sun, 23 Dec 2018 22:44:02 -0500 Subject: [PATCH 067/218] msvc subsystem option handling; added uefi os type --- CMakeLists.txt | 1 + src-self-hosted/target.zig | 2 +- src/all_types.hpp | 3 +- src/analyze.cpp | 12 +++---- src/codegen.cpp | 11 ++---- src/codegen.hpp | 1 - src/ir.cpp | 8 ++++- src/link.cpp | 74 ++++++++++++++++++++++++++++---------- src/main.cpp | 34 +++++++++++++++--- src/target.cpp | 10 ++++-- src/target.hpp | 2 ++ src/translate_c.cpp | 6 ++-- src/zig_llvm.cpp | 7 +++- src/zig_llvm.h | 18 ++++++++-- std/debug/index.zig | 2 +- std/os/index.zig | 7 ++++ std/os/uefi/index.zig | 0 std/special/panic.zig | 2 +- 18 files changed, 150 insertions(+), 50 deletions(-) create mode 100644 std/os/uefi/index.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b64bcca81..7b31f96562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -590,6 +590,7 @@ set(ZIG_STD_FILES "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" + "os/uefi/index.zig" "os/windows/advapi32.zig" "os/windows/error.zig" "os/windows/index.zig" diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 218353c9d7..36381b820d 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -520,7 +520,7 @@ pub const Target = union(enum) { => return 64, }, - builtin.Os.windows => switch (id) { + builtin.Os.windows, builtin.Os.uefi => switch (id) { CInt.Id.Short, CInt.Id.UShort, => return 16, diff --git a/src/all_types.hpp b/src/all_types.hpp index 11304e536d..26e9edbab4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1754,8 +1754,7 @@ struct CodeGen { bool strip_debug_symbols; bool is_test_build; bool is_native_target; - bool windows_subsystem_windows; - bool windows_subsystem_console; + ZigLLVM_MSVCSubsystemType msvc_subsystem; bool linker_rdynamic; bool no_rosegment_workaround; bool each_lib_rpath; diff --git a/src/analyze.cpp b/src/analyze.cpp index 9c24f3cc8d..48d473fb37 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3203,24 +3203,25 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi if (ccc) { if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { g->have_c_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; } else if (buf_eql_str(symbol_name, "WinMain") && g->zig_target.os == OsWindows) { g->have_winmain = true; - g->windows_subsystem_windows = true; - g->windows_subsystem_console = false; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_winmain_crt_startup = true; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_dllmain_crt_startup = true; + g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } } + FnExport *fn_export = fn_table_entry->export_list.add_one(); memset(fn_export, 0, sizeof(FnExport)); buf_init_from_buf(&fn_export->name, symbol_name); @@ -4376,8 +4377,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } diff --git a/src/codegen.cpp b/src/codegen.cpp index e37703d5f0..b76bbfb492 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -291,11 +291,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) { g->darwin_frameworks.append(buf_create_from_str(framework)); } -void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole) { - g->windows_subsystem_windows = mwindows; - g->windows_subsystem_console = mconsole; -} - void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) { g->mmacosx_version_min = mmacosx_version_min; } @@ -7273,7 +7268,7 @@ static void init(CodeGen *g) { // LLVM creates invalid binaries on Windows sometimes. // See https://github.com/ziglang/zig/issues/508 // As a workaround we do not use target native features on Windows. - if (g->zig_target.os == OsWindows) { + if (g->zig_target.os == OsWindows || g->zig_target.os == OsUefi) { target_specific_cpu_args = ""; target_specific_features = ""; } else { @@ -7519,6 +7514,7 @@ static void gen_root_source(CodeGen *g) { report_errors_and_maybe_exit(g); if (!g->is_test_build && g->zig_target.os != OsFreestanding && + g->zig_target.os != OsZen && g->zig_target.os != OsUefi && !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { @@ -8079,8 +8075,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); cache_bool(ch, g->is_native_target); - cache_bool(ch, g->windows_subsystem_windows); - cache_bool(ch, g->windows_subsystem_console); + cache_int(ch, g->msvc_subsystem); cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); cache_bool(ch, g->each_lib_rpath); diff --git a/src/codegen.hpp b/src/codegen.hpp index 1d39e4bf5e..6f1cdfb677 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -33,7 +33,6 @@ void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir); void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir); void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir); void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker); -void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole); void codegen_add_lib_dir(CodeGen *codegen, const char *dir); void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib); LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib); diff --git a/src/ir.cpp b/src/ir.cpp index 83960f2eee..a1432c7b11 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17872,7 +17872,13 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct if (type_is_invalid(cimport_result->value.type)) return ira->codegen->invalid_instruction; - find_libc_include_path(ira->codegen); + if (ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_APPLICATION && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_ROM && + ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_RUNTIME_DRIVER) { + + find_libc_include_path(ira->codegen); + } ImportTableEntry *child_import = allocate(1); child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import); diff --git a/src/link.cpp b/src/link.cpp index 188f976a86..52ca2f2cd9 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -455,7 +455,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append("-NOLOGO"); - if (!g->strip_debug_symbols) { + if (!g->strip_debug_symbols && g->zig_target.os != Os::OsUefi) { lj->args.append("-DEBUG"); } @@ -466,11 +466,6 @@ static void construct_linker_job_coff(LinkJob *lj) { coff_append_machine_arg(g, &lj->args); - if (g->windows_subsystem_windows) { - lj->args.append("/SUBSYSTEM:windows"); - } else if (g->windows_subsystem_console) { - lj->args.append("/SUBSYSTEM:console"); - } // The commented out stuff is from when we linked with MinGW // Now that we're linking with LLD it remains to be determined // how to handle --target-environ gnu @@ -499,18 +494,47 @@ static void construct_linker_job_coff(LinkJob *lj) { // } //} - lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); - if (g->libc_link_lib != nullptr) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir)))); - - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); - if (g->libc_static_lib_dir != nullptr) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); - } + // These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning + // up a bit for building the COFF linker args: + // /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" + // /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" + + // Sorry for the goto(s) :) + switch (g->msvc_subsystem) { + case ZigLLVM_MSVC_CONSOLE: + lj->args.append("/SUBSYSTEM:console"); + goto building_nt; + case ZigLLVM_MSVC_EFI_APPLICATION: + lj->args.append("/SUBSYSTEM:efi_application"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER: + lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_ROM: + lj->args.append("/SUBSYSTEM:efi_rom"); + goto building_uefi; + case ZigLLVM_MSVC_EFI_RUNTIME_DRIVER: + lj->args.append("/SUBSYSTEM:efi_runtime_driver"); + goto building_uefi; + case ZigLLVM_MSVC_NATIVE: + lj->args.append("/SUBSYSTEM:native"); + goto building_nt; + case ZigLLVM_MSVC_POSIX: + lj->args.append("/SUBSYSTEM:posix"); + goto building_nt; + case ZigLLVM_MSVC_WINDOWS: + lj->args.append("/SUBSYSTEM:windows"); + goto building_nt; + case ZigLLVM_MSVC_NONE: + goto continuing_build; } +building_uefi: + lj->args.append("/BASE:\"0\" /ENTRY:\"EfiMain\" /OPT:REF /SAFESEH:NO /MERGE:\".rdata=.data\" /ALIGN:32 /NODEFAULTLIB /SECTION:\".xdata,D\""); + goto continuing_build; + +building_nt: if (lj->link_in_crt) { const char *lib_str = g->is_static ? "lib" : ""; const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; @@ -547,16 +571,30 @@ static void construct_linker_job_coff(LinkJob *lj) { // msvcrt depends on kernel32 lj->args.append("kernel32.lib"); } else { - lj->args.append("-NODEFAULTLIB"); + lj->args.append("/NODEFAULTLIB"); if (!is_library) { if (g->have_winmain) { - lj->args.append("-ENTRY:WinMain"); + lj->args.append("/ENTRY:WinMain"); } else { - lj->args.append("-ENTRY:WinMainCRTStartup"); + lj->args.append("/ENTRY:WinMainCRTStartup"); } } } +continuing_build: + + lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); + + if (g->libc_link_lib != nullptr) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir)))); + + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); + if (g->libc_static_lib_dir != nullptr) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); + } + } + if (is_library && !g->is_static) { lj->args.append("-DLL"); } diff --git a/src/main.cpp b/src/main.cpp index 078dfb25f9..469ec448e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,9 +90,7 @@ static int print_full_usage(const char *arg0) { " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" " --no-rosegment compromise security to workaround valgrind bug\n" - " -mconsole (windows) --subsystem console to the linker\n" - " -mwindows (windows) --subsystem windows to the linker\n" - " -framework [name] (darwin) link against framework\n" + " --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM: to the linker\n" " -framework [name] (darwin) link against framework\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" " --ver-major [ver] dynamic library semver major version\n" @@ -395,6 +393,7 @@ int main(int argc, char **argv) { int runtime_args_start = -1; bool no_rosegment_workaround = false; bool system_linker_hack = false; + ZigLLVM_MSVCSubsystemType msvc_subsystem_type = ZigLLVM_MSVC_NONE; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -540,6 +539,32 @@ int main(int argc, char **argv) { verbose_llvm_ir = true; } else if (strcmp(arg, "--verbose-cimport") == 0) { verbose_cimport = true; + } else if (strcmp(arg, "--msvc-subsystem") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "Expected 1 argument after --msvc-subsystem\n"); + return print_error_usage(arg0); + } + i += 1; + if (stricmp(argv[i], "CONSOLE") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_CONSOLE; + } else if (stricmp(argv[i], "WINDOWS") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_WINDOWS; + } else if (stricmp(argv[i], "POSIX") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_POSIX; + } else if (stricmp(argv[i], "NATIVE") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_NATIVE; + } else if (stricmp(argv[i], "EFI_APPLICATION") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_APPLICATION; + } else if (stricmp(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER; + } else if (stricmp(argv[i], "EFI_ROM") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_ROM; + } else if (stricmp(argv[i], "EFI_RUNTIME_DRIVER") == 0) { + msvc_subsystem_type = ZigLLVM_MSVC_EFI_RUNTIME_DRIVER; + } else { + fprintf(stderr, "Unknown format %s for --msvc-subsystem argument\n", argv[i]); + return EXIT_FAILURE; + } } else if (strcmp(arg, "-mwindows") == 0) { mwindows = true; } else if (strcmp(arg, "-mconsole") == 0) { @@ -849,6 +874,8 @@ int main(int argc, char **argv) { buf_out_name = buf_create_from_str("run"); } CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); + g->msvc_subsystem = msvc_subsystem_type; + if (disable_pic) { if (out_type != OutTypeLib || !is_static) { fprintf(stderr, "--disable-pic only applies to static libraries"); @@ -909,7 +936,6 @@ int main(int argc, char **argv) { codegen_add_rpath(g, rpath_list.at(i)); } - codegen_set_windows_subsystem(g, mwindows, mconsole); codegen_set_rdynamic(g, rdynamic); g->no_rosegment_workaround = no_rosegment_workaround; if (mmacosx_version_min && mios_version_min) { diff --git a/src/target.cpp b/src/target.cpp index 5a4b5252f1..6992f86cac 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -174,6 +174,7 @@ static const Os os_list[] = { OsContiki, OsAMDPAL, OsZen, + OsUefi, }; // Coordinate with zig_llvm.h @@ -315,6 +316,8 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) { return ZigLLVM_Contiki; case OsAMDPAL: return ZigLLVM_AMDPAL; + case OsUefi: + return ZigLLVM_Uefi; } zig_unreachable(); } @@ -756,6 +759,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case CIntTypeCount: zig_unreachable(); } + case OsUefi: case OsWindows: switch (id) { case CIntTypeShort: @@ -803,7 +807,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { } const char *target_o_file_ext(ZigTarget *target) { - if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows) { + if (target->env_type == ZigLLVM_MSVC || (target->os == OsWindows || target->os == OsUefi)) { return ".obj"; } else { return ".o"; @@ -821,13 +825,15 @@ const char *target_llvm_ir_file_ext(ZigTarget *target) { const char *target_exe_file_ext(ZigTarget *target) { if (target->os == OsWindows) { return ".exe"; + } else if (target->os == OsUefi) { + return ".efi"; } else { return ""; } } const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) { - if (target->os == OsWindows) { + if (target->os == OsWindows || target->os == OsUefi) { if (is_static) { return ".lib"; } else { diff --git a/src/target.hpp b/src/target.hpp index 04652179d2..62cc20711a 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -51,6 +51,7 @@ enum Os { OsContiki, OsAMDPAL, OsZen, + OsUefi, }; struct ZigTarget { @@ -59,6 +60,7 @@ struct ZigTarget { Os os; ZigLLVM_EnvironmentType env_type; ZigLLVM_ObjectFormatType oformat; + ZigLLVM_MSVCSubsystemType msvc_subsystem = ZigLLVM_MSVC_NONE; }; enum CIntType { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index f6bc9cd683..0e56e29810 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4749,8 +4749,10 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const clang_argv.append("-isystem"); clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); - clang_argv.append("-isystem"); - clang_argv.append(buf_ptr(codegen->libc_include_dir)); + if (codegen->libc_include_dir) { + clang_argv.append("-isystem"); + clang_argv.append(buf_ptr(codegen->libc_include_dir)); + } // windows c runtime requires -D_DEBUG if using debug libraries if (codegen->build_mode == BuildModeDebug) { diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index bda8fa0adc..bd63b7cbe5 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -690,7 +690,12 @@ const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor) { } const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os) { - return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); + switch (os) { + case ZigLLVM_Uefi: + return "windows"; + default: + return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); + } } const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 551a4a7448..bb7cb5c5ff 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -357,8 +358,8 @@ enum ZigLLVM_OSType { ZigLLVM_Mesa3D, ZigLLVM_Contiki, ZigLLVM_AMDPAL, // AMD PAL Runtime - - ZigLLVM_LastOSType = ZigLLVM_AMDPAL + ZigLLVM_Uefi, + ZigLLVM_LastOSType = ZigLLVM_Uefi }; // Synchronize with target.cpp::environ_list @@ -397,6 +398,19 @@ enum ZigLLVM_ObjectFormatType { ZigLLVM_Wasm, }; +// For MSVC-supported subsystems +enum ZigLLVM_MSVCSubsystemType { + ZigLLVM_MSVC_NONE, + ZigLLVM_MSVC_CONSOLE, + ZigLLVM_MSVC_WINDOWS, + ZigLLVM_MSVC_POSIX, + ZigLLVM_MSVC_NATIVE, + ZigLLVM_MSVC_EFI_APPLICATION, + ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER, + ZigLLVM_MSVC_EFI_ROM, + ZigLLVM_MSVC_EFI_RUNTIME_DRIVER, +}; + ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch); ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); diff --git a/std/debug/index.zig b/std/debug/index.zig index 73c6ea7b56..93d6a60a03 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1135,7 +1135,7 @@ pub const DebugInfo = switch (builtin.os) { return self.ofiles.allocator; } }, - builtin.Os.windows => struct { + builtin.Os.uefi, builtin.Os.windows => struct { pdb: pdb.Pdb, coff: *coff.Coff, sect_contribs: []pdb.SectionContribEntry, diff --git a/std/os/index.zig b/std/os/index.zig index b19679c969..ce65667157 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -18,6 +18,7 @@ test "std.os" { _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); + _ = @import("uefi/index.zig"); _ = @import("get_app_data_dir.zig"); } @@ -26,6 +27,8 @@ pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); pub const freebsd = @import("freebsd/index.zig"); pub const zen = @import("zen.zig"); +pub const uefi = @import("uefi/index.zig"); + pub const posix = switch (builtin.os) { Os.linux => linux, Os.macosx, Os.ios => darwin, @@ -33,6 +36,7 @@ pub const posix = switch (builtin.os) { Os.zen => zen, else => @compileError("Unsupported OS"), }; + pub const net = @import("net.zig"); pub const ChildProcess = @import("child_process.zig").ChildProcess; @@ -187,6 +191,9 @@ pub fn abort() noreturn { } windows.ExitProcess(3); }, + Os.uefi => { + while (true) {} + }, else => @compileError("Unsupported OS"), } } diff --git a/std/os/uefi/index.zig b/std/os/uefi/index.zig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/std/special/panic.zig b/std/special/panic.zig index ca1caea73c..fe1e020604 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -10,7 +10,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn @setCold(true); switch (builtin.os) { // TODO: fix panic in zen. - builtin.Os.freestanding, builtin.Os.zen => { + builtin.Os.freestanding, builtin.Os.zen, builtin.Os.uefi => { while (true) {} }, else => { From 480061d2c999375be1442d14451da15d6662e67d Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Sun, 23 Dec 2018 23:09:07 -0500 Subject: [PATCH 068/218] git user error fix --- src/codegen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index b76bbfb492..30a4f8c2a4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7231,8 +7231,7 @@ static void init(CodeGen *g) { } if (g->is_test_build) { - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; } assert(g->root_out_name); From 51baea184bb2bcfb325caf3c5051118deadc319d Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Sun, 23 Dec 2018 23:46:45 -0500 Subject: [PATCH 069/218] Yet another git user error remnant fixed --- src/target.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target.cpp b/src/target.cpp index 6992f86cac..973662757b 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -397,6 +397,8 @@ const char *get_target_os_name(Os os_type) { return "freestanding"; case OsZen: return "zen"; + case OsUefi: + return "uefi"; case OsAnanas: case OsCloudABI: case OsDragonFly: From 7dcee99510fe4d69faae67f3aa41cfb47a43045e Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Sun, 23 Dec 2018 23:59:59 -0500 Subject: [PATCH 070/218] fixed stricmp/strcasecmp between windows/posix --- src/main.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 469ec448e8..303e48d750 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,13 @@ #include +#ifdef __GNUC__ +#include +#define STRCASECMP strcasecmp +#else +#define STRCASECMP stricmp +#endif + static int print_error_usage(const char *arg0) { fprintf(stderr, "See `%s help` for detailed usage information\n", arg0); return EXIT_FAILURE; @@ -545,21 +552,21 @@ int main(int argc, char **argv) { return print_error_usage(arg0); } i += 1; - if (stricmp(argv[i], "CONSOLE") == 0) { + if (STRCASECMP(argv[i], "CONSOLE") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_CONSOLE; - } else if (stricmp(argv[i], "WINDOWS") == 0) { + } else if (STRCASECMP(argv[i], "WINDOWS") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_WINDOWS; - } else if (stricmp(argv[i], "POSIX") == 0) { + } else if (STRCASECMP(argv[i], "POSIX") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_POSIX; - } else if (stricmp(argv[i], "NATIVE") == 0) { + } else if (STRCASECMP(argv[i], "NATIVE") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_NATIVE; - } else if (stricmp(argv[i], "EFI_APPLICATION") == 0) { + } else if (STRCASECMP(argv[i], "EFI_APPLICATION") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_EFI_APPLICATION; - } else if (stricmp(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) { + } else if (STRCASECMP(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER; - } else if (stricmp(argv[i], "EFI_ROM") == 0) { + } else if (STRCASECMP(argv[i], "EFI_ROM") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_EFI_ROM; - } else if (stricmp(argv[i], "EFI_RUNTIME_DRIVER") == 0) { + } else if (STRCASECMP(argv[i], "EFI_RUNTIME_DRIVER") == 0) { msvc_subsystem_type = ZigLLVM_MSVC_EFI_RUNTIME_DRIVER; } else { fprintf(stderr, "Unknown format %s for --msvc-subsystem argument\n", argv[i]); From de473d442371c943bff077428b3786885cadec47 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Mon, 24 Dec 2018 10:27:08 -0200 Subject: [PATCH 071/218] freebsd: implement std.os.time.sleep --- std/os/time.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/time.zig b/std/os/time.zig index d9fe046a55..c3588838bc 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -13,7 +13,7 @@ pub const epoch = @import("epoch.zig"); /// Sleep for the specified duration pub fn sleep(nanoseconds: u64) void { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const s = nanoseconds / ns_per_s; const ns = nanoseconds % ns_per_s; posixSleep(@intCast(u63, s), @intCast(u63, ns)); From 28cd337d1ffc547f296f574b82547d6b15253167 Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Mon, 24 Dec 2018 07:49:15 -0500 Subject: [PATCH 072/218] fixed formatting in options display --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 303e48d750..faca9511dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -97,7 +97,8 @@ static int print_full_usage(const char *arg0) { " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" " --no-rosegment compromise security to workaround valgrind bug\n" - " --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM: to the linker\n" " -framework [name] (darwin) link against framework\n" + " --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM: to the linker\n" + " -framework [name] (darwin) link against framework\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" " --ver-major [ver] dynamic library semver major version\n" From 52be7d7404acf2eff53d5c0cfd3ddeb591a5e27c Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Mon, 24 Dec 2018 11:19:09 -0200 Subject: [PATCH 073/218] freebsd: fix flags for opening files Prior to this fix, the compare-outputs test suite was showing a strange behavior, the tests always stopped between tests 6-8 and had a stack track similar to each other. ``` Test 8/68 compare-output multiple files with private function (ReleaseSmall)...OK /usr/home/mgxm/dev/zig/zig-cache/source.zig:7:2: error: invalid token: '&' }&(getStdOut() catch unreachable).outStream().stream; ^ The following command exited with error code 1: ``` With the wrong O_* flags, the source code was being written in append mode which resulted in an invalid file ```zig use @import("foo.zig"); use @import("bar.zig"); pub fn main() void { foo_function(); bar_function(); }&(getStdOut() catch unreachable).outStream().stream; stdout.print("OK 2\n") catch unreachable; } fn privateFunction() void { printText(); } ``` --- std/os/freebsd/index.zig | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index ebea64fdf6..603265b956 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -105,26 +105,26 @@ pub const W_OK = 2; // test for write permission pub const R_OK = 4; // test for read permission -pub const O_RDONLY = 0o0; -pub const O_WRONLY = 0o1; -pub const O_RDWR = 0o2; -pub const O_ACCMODE = 0o3; +pub const O_RDONLY = 0x0000; +pub const O_WRONLY = 0x0001; +pub const O_RDWR = 0x0002; +pub const O_ACCMODE = 0x0003; -pub const O_CREAT = 0o100; -pub const O_EXCL = 0o200; -pub const O_NOCTTY = 0o400; -pub const O_TRUNC = 0o1000; -pub const O_APPEND = 0o2000; -pub const O_NONBLOCK = 0o4000; +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 = 0o4010000; +pub const O_SYNC = 0x0080; pub const O_RSYNC = 0o4010000; pub const O_DIRECTORY = 0o200000; -pub const O_NOFOLLOW = 0o400000; -pub const O_CLOEXEC = 0o2000000; +pub const O_NOFOLLOW = 0x0100; +pub const O_CLOEXEC = 0x00100000; -pub const O_ASYNC = 0o20000; -pub const O_DIRECT = 0o40000; +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; From f49b45b00fbdf3feaea7d8460bdbfd5935ff1ea1 Mon Sep 17 00:00:00 2001 From: nebulaeonline Date: Mon, 24 Dec 2018 14:01:35 -0500 Subject: [PATCH 074/218] tabs to space fix. thanks visual studio. --- src/target.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target.cpp b/src/target.cpp index 973662757b..61543c38d5 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -397,8 +397,8 @@ const char *get_target_os_name(Os os_type) { return "freestanding"; case OsZen: return "zen"; - case OsUefi: - return "uefi"; + case OsUefi: + return "uefi"; case OsAnanas: case OsCloudABI: case OsDragonFly: From 4a1f0e141893fe56f540709c8fb12b8b8dc22218 Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 26 Dec 2018 10:31:45 -0600 Subject: [PATCH 075/218] Switching on bools with duplicate and missing value detection: Issue 1768 --- src/ir.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index 83960f2eee..b1429ae8ac 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19787,6 +19787,39 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_instruction; } } + } else if (switch_type->id == ZigTypeIdBool) { + int seenTrue = 0; + int seenFalse = 0; + for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { + IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; + + IrInstruction *value = range->start->child; + + IrInstruction *casted_value = ir_implicit_cast(ira, value, switch_type); + if (type_is_invalid(casted_value->value.type)) + return ira->codegen->invalid_instruction; + + ConstExprValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_expr_val) + return ira->codegen->invalid_instruction; + + assert(const_expr_val->type->id == ZigTypeIdBool); + + if (const_expr_val->data.x_bool == true) { + seenTrue += 1; + } else { + seenFalse += 1; + } + + if ((seenTrue > 1) || (seenFalse > 1)) { + ir_add_error(ira, value, buf_sprintf("duplicate switch value")); + return ira->codegen->invalid_instruction; + } + } + if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) { + ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities")); + return ira->codegen->invalid_instruction; + } } else if (!instruction->have_else_prong) { ir_add_error(ira, &instruction->base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); From a918ce26b81b8e51c061d85631aa432a025c1ee2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Dec 2018 15:25:54 -0500 Subject: [PATCH 076/218] fixups --- CMakeLists.txt | 2 +- README.md | 40 +++--- src/all_types.hpp | 2 +- src/analyze.cpp | 8 +- src/codegen.cpp | 6 +- src/ir.cpp | 8 +- src/link.cpp | 310 ++++++++++++++++++++++-------------------- src/main.cpp | 78 +++++------ src/target.cpp | 5 +- src/target.hpp | 13 +- src/translate_c.cpp | 2 +- src/zig_llvm.cpp | 7 +- src/zig_llvm.h | 18 +-- std/os/index.zig | 5 +- std/os/uefi.zig | 2 + std/os/uefi/index.zig | 0 std/special/panic.zig | 6 +- 17 files changed, 253 insertions(+), 259 deletions(-) create mode 100644 std/os/uefi.zig delete mode 100644 std/os/uefi/index.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b31f96562..807077476a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -590,7 +590,7 @@ set(ZIG_STD_FILES "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" - "os/uefi/index.zig" + "os/uefi.zig" "os/windows/advapi32.zig" "os/windows/error.zig" "os/windows/index.zig" diff --git a/README.md b/README.md index c1eec599e5..e9756b404d 100644 --- a/README.md +++ b/README.md @@ -87,26 +87,26 @@ clarity. #### Support Table -| | freestanding | linux | macosx | windows | freebsd | other | -|--------|--------------|--------|--------|---------|---------|--------| -|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 3 | -|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | -|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | -|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | -|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | -|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | -|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | -|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | -|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | +| | freestanding | linux | macosx | windows | freebsd | UEFI | other | +|--------|--------------|--------|--------|---------|---------|--------|--------| +|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 | +|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | +|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | +|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | +|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | +|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | +|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | +|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | +|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | ## Community diff --git a/src/all_types.hpp b/src/all_types.hpp index 26e9edbab4..2b55f8ee2e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1750,11 +1750,11 @@ struct CodeGen { BuildMode build_mode; OutType out_type; ZigTarget zig_target; + TargetSubsystem subsystem; bool is_static; bool strip_debug_symbols; bool is_test_build; bool is_native_target; - ZigLLVM_MSVCSubsystemType msvc_subsystem; bool linker_rdynamic; bool no_rosegment_workaround; bool each_lib_rpath; diff --git a/src/analyze.cpp b/src/analyze.cpp index 48d473fb37..04d957b626 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3203,22 +3203,20 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi if (ccc) { if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { g->have_c_main = true; - g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; + g->subsystem = TargetSubsystemConsole; } else if (buf_eql_str(symbol_name, "WinMain") && g->zig_target.os == OsWindows) { g->have_winmain = true; - g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; + g->subsystem = TargetSubsystemWindows; } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_winmain_crt_startup = true; - g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && g->zig_target.os == OsWindows) { g->have_dllmain_crt_startup = true; - g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS; } } @@ -4377,7 +4375,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; + g->subsystem = TargetSubsystemConsole; } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } diff --git a/src/codegen.cpp b/src/codegen.cpp index 30a4f8c2a4..bbf8ffa340 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7231,7 +7231,7 @@ static void init(CodeGen *g) { } if (g->is_test_build) { - g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE; + g->subsystem = TargetSubsystemConsole; } assert(g->root_out_name); @@ -7513,7 +7513,7 @@ static void gen_root_source(CodeGen *g) { report_errors_and_maybe_exit(g); if (!g->is_test_build && g->zig_target.os != OsFreestanding && - g->zig_target.os != OsZen && g->zig_target.os != OsUefi && + g->zig_target.os != OsUefi && !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { @@ -8070,11 +8070,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_int(ch, g->zig_target.os); cache_int(ch, g->zig_target.env_type); cache_int(ch, g->zig_target.oformat); + cache_int(ch, g->subsystem); cache_bool(ch, g->is_static); cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); cache_bool(ch, g->is_native_target); - cache_int(ch, g->msvc_subsystem); cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); cache_bool(ch, g->each_lib_rpath); diff --git a/src/ir.cpp b/src/ir.cpp index a1432c7b11..83960f2eee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17872,13 +17872,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct if (type_is_invalid(cimport_result->value.type)) return ira->codegen->invalid_instruction; - if (ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_APPLICATION && - ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER && - ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_ROM && - ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_RUNTIME_DRIVER) { - - find_libc_include_path(ira->codegen); - } + find_libc_include_path(ira->codegen); ImportTableEntry *child_import = allocate(1); child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import); diff --git a/src/link.cpp b/src/link.cpp index 52ca2f2cd9..593f7f309f 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -444,97 +444,20 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si return ZigLLDLink(oformat, args, arg_count, link_diag_callback, diag); } -static void construct_linker_job_coff(LinkJob *lj) { +static void add_uefi_link_args(LinkJob *lj) { + lj->args.append("/BASE:0"); + lj->args.append("/ENTRY:EfiMain"); + lj->args.append("/OPT:REF"); + lj->args.append("/SAFESEH:NO"); + lj->args.append("/MERGE:.rdata=.data"); + lj->args.append("/ALIGN:32"); + lj->args.append("/NODEFAULTLIB"); + lj->args.append("/SECTION:.xdata,D"); +} + +static void add_nt_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; - lj->args.append("/ERRORLIMIT:0"); - - if (g->libc_link_lib != nullptr) { - find_libc_lib_path(g); - } - - lj->args.append("-NOLOGO"); - - if (!g->strip_debug_symbols && g->zig_target.os != Os::OsUefi) { - lj->args.append("-DEBUG"); - } - - if (g->out_type == OutTypeExe) { - // TODO compile time stack upper bound detection - lj->args.append("/STACK:16777216"); - } - - coff_append_machine_arg(g, &lj->args); - - // The commented out stuff is from when we linked with MinGW - // Now that we're linking with LLD it remains to be determined - // how to handle --target-environ gnu - // These comments are a clue - - bool is_library = g->out_type == OutTypeLib; - //bool dll = g->out_type == OutTypeLib; - //bool shared = !g->is_static && dll; - //if (g->is_static) { - // lj->args.append("-Bstatic"); - //} else { - // if (dll) { - // lj->args.append("--dll"); - // } else if (shared) { - // lj->args.append("--shared"); - // } - // lj->args.append("-Bdynamic"); - // if (dll || shared) { - // lj->args.append("-e"); - // if (g->zig_target.arch.arch == ZigLLVM_x86) { - // lj->args.append("_DllMainCRTStartup@12"); - // } else { - // lj->args.append("DllMainCRTStartup"); - // } - // lj->args.append("--enable-auto-image-base"); - // } - //} - - - // These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning - // up a bit for building the COFF linker args: - // /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" - // /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" - - // Sorry for the goto(s) :) - switch (g->msvc_subsystem) { - case ZigLLVM_MSVC_CONSOLE: - lj->args.append("/SUBSYSTEM:console"); - goto building_nt; - case ZigLLVM_MSVC_EFI_APPLICATION: - lj->args.append("/SUBSYSTEM:efi_application"); - goto building_uefi; - case ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER: - lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); - goto building_uefi; - case ZigLLVM_MSVC_EFI_ROM: - lj->args.append("/SUBSYSTEM:efi_rom"); - goto building_uefi; - case ZigLLVM_MSVC_EFI_RUNTIME_DRIVER: - lj->args.append("/SUBSYSTEM:efi_runtime_driver"); - goto building_uefi; - case ZigLLVM_MSVC_NATIVE: - lj->args.append("/SUBSYSTEM:native"); - goto building_nt; - case ZigLLVM_MSVC_POSIX: - lj->args.append("/SUBSYSTEM:posix"); - goto building_nt; - case ZigLLVM_MSVC_WINDOWS: - lj->args.append("/SUBSYSTEM:windows"); - goto building_nt; - case ZigLLVM_MSVC_NONE: - goto continuing_build; - } - -building_uefi: - lj->args.append("/BASE:\"0\" /ENTRY:\"EfiMain\" /OPT:REF /SAFESEH:NO /MERGE:\".rdata=.data\" /ALIGN:32 /NODEFAULTLIB /SECTION:\".xdata,D\""); - goto continuing_build; - -building_nt: if (lj->link_in_crt) { const char *lib_str = g->is_static ? "lib" : ""; const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; @@ -557,17 +480,6 @@ building_nt: //https://msdn.microsoft.com/en-us/library/bb531344.aspx lj->args.append("legacy_stdio_definitions.lib"); - //if (shared || dll) { - // lj->args.append(get_libc_file(g, "dllcrt2.o")); - //} else { - // if (g->windows_linker_unicode) { - // lj->args.append(get_libc_file(g, "crt2u.o")); - // } else { - // lj->args.append(get_libc_file(g, "crt2.o")); - // } - //} - //lj->args.append(get_libc_static_file(g, "crtbegin.o")); - // msvcrt depends on kernel32 lj->args.append("kernel32.lib"); } else { @@ -580,8 +492,156 @@ building_nt: } } } +} -continuing_build: +// These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning +// up a bit for building the COFF linker args: +// /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" +// /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D" +// This commented out stuff is from when we linked with MinGW +// Now that we're linking with LLD it remains to be determined +// how to handle --target-environ gnu +// These comments are a clue +//bool dll = g->out_type == OutTypeLib; +//bool shared = !g->is_static && dll; +//if (g->is_static) { +// lj->args.append("-Bstatic"); +//} else { +// if (dll) { +// lj->args.append("--dll"); +// } else if (shared) { +// lj->args.append("--shared"); +// } +// lj->args.append("-Bdynamic"); +// if (dll || shared) { +// lj->args.append("-e"); +// if (g->zig_target.arch.arch == ZigLLVM_x86) { +// lj->args.append("_DllMainCRTStartup@12"); +// } else { +// lj->args.append("DllMainCRTStartup"); +// } +// lj->args.append("--enable-auto-image-base"); +// } +//} +//if (shared || dll) { +// lj->args.append(get_libc_file(g, "dllcrt2.o")); +//} else { +// if (g->windows_linker_unicode) { +// lj->args.append(get_libc_file(g, "crt2u.o")); +// } else { +// lj->args.append(get_libc_file(g, "crt2.o")); +// } +//} +//lj->args.append(get_libc_static_file(g, "crtbegin.o")); +//if (g->libc_link_lib != nullptr) { +//if (g->is_static) { +// lj->args.append("--start-group"); +//} + +//lj->args.append("-lmingw32"); + +//lj->args.append("-lgcc"); +//bool is_android = (g->zig_target.env_type == ZigLLVM_Android); +//bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target); +//if (!g->is_static && !is_android) { +// if (!is_cyg_ming) { +// lj->args.append("--as-needed"); +// } +// //lj->args.append("-lgcc_s"); +// if (!is_cyg_ming) { +// lj->args.append("--no-as-needed"); +// } +//} +//if (g->is_static && !is_android) { +// //lj->args.append("-lgcc_eh"); +//} +//if (is_android && !g->is_static) { +// lj->args.append("-ldl"); +//} + +//lj->args.append("-lmoldname"); +//lj->args.append("-lmingwex"); +//lj->args.append("-lmsvcrt"); + + +//if (g->windows_subsystem_windows) { +// lj->args.append("-lgdi32"); +// lj->args.append("-lcomdlg32"); +//} +//lj->args.append("-ladvapi32"); +//lj->args.append("-lshell32"); +//lj->args.append("-luser32"); +//lj->args.append("-lkernel32"); + +//if (g->is_static) { +// lj->args.append("--end-group"); +//} + +//if (lj->link_in_crt) { +// lj->args.append(get_libc_static_file(g, "crtend.o")); +//} +//} + + +static void construct_linker_job_coff(LinkJob *lj) { + CodeGen *g = lj->codegen; + + lj->args.append("/ERRORLIMIT:0"); + + if (g->libc_link_lib != nullptr) { + find_libc_lib_path(g); + } + + lj->args.append("/NOLOGO"); + + if (!g->strip_debug_symbols) { + lj->args.append("/DEBUG"); + } + + if (g->out_type == OutTypeExe) { + // TODO compile time stack upper bound detection + lj->args.append("/STACK:16777216"); + } + + coff_append_machine_arg(g, &lj->args); + + bool is_library = g->out_type == OutTypeLib; + switch (g->subsystem) { + case TargetSubsystemAuto: + break; + case TargetSubsystemConsole: + lj->args.append("/SUBSYSTEM:console"); + add_nt_link_args(lj, is_library); + break; + case TargetSubsystemEfiApplication: + lj->args.append("/SUBSYSTEM:efi_application"); + add_uefi_link_args(lj); + break; + case TargetSubsystemEfiBootServiceDriver: + lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); + add_uefi_link_args(lj); + break; + case TargetSubsystemEfiRom: + lj->args.append("/SUBSYSTEM:efi_rom"); + add_uefi_link_args(lj); + break; + case TargetSubsystemEfiRuntimeDriver: + lj->args.append("/SUBSYSTEM:efi_runtime_driver"); + add_uefi_link_args(lj); + break; + case TargetSubsystemNative: + lj->args.append("/SUBSYSTEM:native"); + add_nt_link_args(lj, is_library); + break; + case TargetSubsystemPosix: + lj->args.append("/SUBSYSTEM:posix"); + add_nt_link_args(lj, is_library); + break; + case TargetSubsystemWindows: + lj->args.append("/SUBSYSTEM:windows"); + add_nt_link_args(lj, is_library); + break; + } lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); @@ -665,54 +725,6 @@ continuing_build: } } - //if (g->libc_link_lib != nullptr) { - //if (g->is_static) { - // lj->args.append("--start-group"); - //} - - //lj->args.append("-lmingw32"); - - //lj->args.append("-lgcc"); - //bool is_android = (g->zig_target.env_type == ZigLLVM_Android); - //bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target); - //if (!g->is_static && !is_android) { - // if (!is_cyg_ming) { - // lj->args.append("--as-needed"); - // } - // //lj->args.append("-lgcc_s"); - // if (!is_cyg_ming) { - // lj->args.append("--no-as-needed"); - // } - //} - //if (g->is_static && !is_android) { - // //lj->args.append("-lgcc_eh"); - //} - //if (is_android && !g->is_static) { - // lj->args.append("-ldl"); - //} - - //lj->args.append("-lmoldname"); - //lj->args.append("-lmingwex"); - //lj->args.append("-lmsvcrt"); - - - //if (g->windows_subsystem_windows) { - // lj->args.append("-lgdi32"); - // lj->args.append("-lcomdlg32"); - //} - //lj->args.append("-ladvapi32"); - //lj->args.append("-lshell32"); - //lj->args.append("-luser32"); - //lj->args.append("-lkernel32"); - - //if (g->is_static) { - // lj->args.append("--end-group"); - //} - - //if (lj->link_in_crt) { - // lj->args.append(get_libc_static_file(g, "crtend.o")); - //} - //} } diff --git a/src/main.cpp b/src/main.cpp index faca9511dc..fd8e3db2fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,13 +16,6 @@ #include -#ifdef __GNUC__ -#include -#define STRCASECMP strcasecmp -#else -#define STRCASECMP stricmp -#endif - static int print_error_usage(const char *arg0) { fprintf(stderr, "See `%s help` for detailed usage information\n", arg0); return EXIT_FAILURE; @@ -97,8 +90,8 @@ static int print_full_usage(const char *arg0) { " -rdynamic add all symbols to the dynamic symbol table\n" " -rpath [path] add directory to the runtime library search path\n" " --no-rosegment compromise security to workaround valgrind bug\n" - " --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM: to the linker\n" - " -framework [name] (darwin) link against framework\n" + " --subsystem [subsystem] (windows) /SUBSYSTEM: to the linker\n" + " -framework [name] (darwin) link against framework\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n" " --ver-major [ver] dynamic library semver major version\n" @@ -377,8 +370,6 @@ int main(int argc, char **argv) { const char *target_arch = nullptr; const char *target_os = nullptr; const char *target_environ = nullptr; - bool mwindows = false; - bool mconsole = false; bool rdynamic = false; const char *mmacosx_version_min = nullptr; const char *mios_version_min = nullptr; @@ -401,7 +392,7 @@ int main(int argc, char **argv) { int runtime_args_start = -1; bool no_rosegment_workaround = false; bool system_linker_hack = false; - ZigLLVM_MSVCSubsystemType msvc_subsystem_type = ZigLLVM_MSVC_NONE; + TargetSubsystem subsystem = TargetSubsystemAuto; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -547,36 +538,6 @@ int main(int argc, char **argv) { verbose_llvm_ir = true; } else if (strcmp(arg, "--verbose-cimport") == 0) { verbose_cimport = true; - } else if (strcmp(arg, "--msvc-subsystem") == 0) { - if (i + 1 >= argc) { - fprintf(stderr, "Expected 1 argument after --msvc-subsystem\n"); - return print_error_usage(arg0); - } - i += 1; - if (STRCASECMP(argv[i], "CONSOLE") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_CONSOLE; - } else if (STRCASECMP(argv[i], "WINDOWS") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_WINDOWS; - } else if (STRCASECMP(argv[i], "POSIX") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_POSIX; - } else if (STRCASECMP(argv[i], "NATIVE") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_NATIVE; - } else if (STRCASECMP(argv[i], "EFI_APPLICATION") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_EFI_APPLICATION; - } else if (STRCASECMP(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER; - } else if (STRCASECMP(argv[i], "EFI_ROM") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_EFI_ROM; - } else if (STRCASECMP(argv[i], "EFI_RUNTIME_DRIVER") == 0) { - msvc_subsystem_type = ZigLLVM_MSVC_EFI_RUNTIME_DRIVER; - } else { - fprintf(stderr, "Unknown format %s for --msvc-subsystem argument\n", argv[i]); - return EXIT_FAILURE; - } - } else if (strcmp(arg, "-mwindows") == 0) { - mwindows = true; - } else if (strcmp(arg, "-mconsole") == 0) { - mconsole = true; } else if (strcmp(arg, "-rdynamic") == 0) { rdynamic = true; } else if (strcmp(arg, "--no-rosegment") == 0) { @@ -720,6 +681,37 @@ int main(int argc, char **argv) { ver_patch = atoi(argv[i]); } else if (strcmp(arg, "--test-cmd") == 0) { test_exec_args.append(argv[i]); + } else if (strcmp(arg, "--subsystem") == 0) { + if (strcmp(argv[i], "console") == 0) { + subsystem = TargetSubsystemConsole; + } else if (strcmp(argv[i], "windows") == 0) { + subsystem = TargetSubsystemWindows; + } else if (strcmp(argv[i], "posix") == 0) { + subsystem = TargetSubsystemPosix; + } else if (strcmp(argv[i], "native") == 0) { + subsystem = TargetSubsystemNative; + } else if (strcmp(argv[i], "efi_application") == 0) { + subsystem = TargetSubsystemEfiApplication; + } else if (strcmp(argv[i], "efi_boot_service_driver") == 0) { + subsystem = TargetSubsystemEfiBootServiceDriver; + } else if (strcmp(argv[i], "efi_rom") == 0) { + subsystem = TargetSubsystemEfiRom; + } else if (strcmp(argv[i], "efi_runtime_driver") == 0) { + subsystem = TargetSubsystemEfiRuntimeDriver; + } else { + fprintf(stderr, "invalid: --subsystem %s\n" + "Options are:\n" + " console\n" + " windows\n" + " posix\n" + " native\n" + " efi_application\n" + " efi_boot_service_driver\n" + " efi_rom\n" + " efi_runtime_driver\n" + , argv[i]); + return EXIT_FAILURE; + } } else { fprintf(stderr, "Invalid argument: %s\n", arg); return print_error_usage(arg0); @@ -882,7 +874,7 @@ int main(int argc, char **argv) { buf_out_name = buf_create_from_str("run"); } CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); - g->msvc_subsystem = msvc_subsystem_type; + g->subsystem = subsystem; if (disable_pic) { if (out_type != OutTypeLib || !is_static) { diff --git a/src/target.cpp b/src/target.cpp index 61543c38d5..6fea79518c 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -283,6 +283,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) { case OsSolaris: return ZigLLVM_Solaris; case OsWindows: + case OsUefi: return ZigLLVM_Win32; case OsHaiku: return ZigLLVM_Haiku; @@ -316,8 +317,6 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) { return ZigLLVM_Contiki; case OsAMDPAL: return ZigLLVM_AMDPAL; - case OsUefi: - return ZigLLVM_Uefi; } zig_unreachable(); } @@ -809,7 +808,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { } const char *target_o_file_ext(ZigTarget *target) { - if (target->env_type == ZigLLVM_MSVC || (target->os == OsWindows || target->os == OsUefi)) { + if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) { return ".obj"; } else { return ".o"; diff --git a/src/target.hpp b/src/target.hpp index 62cc20711a..a87b12351a 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -54,13 +54,24 @@ enum Os { OsUefi, }; +enum TargetSubsystem { + TargetSubsystemAuto, // Zig should infer the subsystem + TargetSubsystemConsole, + TargetSubsystemWindows, + TargetSubsystemPosix, + TargetSubsystemNative, + TargetSubsystemEfiApplication, + TargetSubsystemEfiBootServiceDriver, + TargetSubsystemEfiRom, + TargetSubsystemEfiRuntimeDriver, +}; + struct ZigTarget { ArchType arch; ZigLLVM_VendorType vendor; Os os; ZigLLVM_EnvironmentType env_type; ZigLLVM_ObjectFormatType oformat; - ZigLLVM_MSVCSubsystemType msvc_subsystem = ZigLLVM_MSVC_NONE; }; enum CIntType { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 0e56e29810..02fa3b24be 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4749,7 +4749,7 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const clang_argv.append("-isystem"); clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); - if (codegen->libc_include_dir) { + if (codegen->libc_include_dir != nullptr) { clang_argv.append("-isystem"); clang_argv.append(buf_ptr(codegen->libc_include_dir)); } diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index bd63b7cbe5..bda8fa0adc 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -690,12 +690,7 @@ const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor) { } const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os) { - switch (os) { - case ZigLLVM_Uefi: - return "windows"; - default: - return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); - } + return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); } const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index bb7cb5c5ff..551a4a7448 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -358,8 +357,8 @@ enum ZigLLVM_OSType { ZigLLVM_Mesa3D, ZigLLVM_Contiki, ZigLLVM_AMDPAL, // AMD PAL Runtime - ZigLLVM_Uefi, - ZigLLVM_LastOSType = ZigLLVM_Uefi + + ZigLLVM_LastOSType = ZigLLVM_AMDPAL }; // Synchronize with target.cpp::environ_list @@ -398,19 +397,6 @@ enum ZigLLVM_ObjectFormatType { ZigLLVM_Wasm, }; -// For MSVC-supported subsystems -enum ZigLLVM_MSVCSubsystemType { - ZigLLVM_MSVC_NONE, - ZigLLVM_MSVC_CONSOLE, - ZigLLVM_MSVC_WINDOWS, - ZigLLVM_MSVC_POSIX, - ZigLLVM_MSVC_NATIVE, - ZigLLVM_MSVC_EFI_APPLICATION, - ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER, - ZigLLVM_MSVC_EFI_ROM, - ZigLLVM_MSVC_EFI_RUNTIME_DRIVER, -}; - ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch); ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); diff --git a/std/os/index.zig b/std/os/index.zig index ce65667157..bb2eb76265 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -18,7 +18,7 @@ test "std.os" { _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); - _ = @import("uefi/index.zig"); + _ = @import("uefi.zig"); _ = @import("get_app_data_dir.zig"); } @@ -27,7 +27,7 @@ pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); pub const freebsd = @import("freebsd/index.zig"); pub const zen = @import("zen.zig"); -pub const uefi = @import("uefi/index.zig"); +pub const uefi = @import("uefi.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, @@ -192,6 +192,7 @@ pub fn abort() noreturn { 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"), diff --git a/std/os/uefi.zig b/std/os/uefi.zig new file mode 100644 index 0000000000..8ed60d9c9b --- /dev/null +++ b/std/os/uefi.zig @@ -0,0 +1,2 @@ +// TODO this is where the extern declarations go. For example, see +// inc/efilib.h in gnu-efi-code diff --git a/std/os/uefi/index.zig b/std/os/uefi/index.zig deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/std/special/panic.zig b/std/special/panic.zig index fe1e020604..bd3ad971e0 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -10,9 +10,13 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn @setCold(true); switch (builtin.os) { // TODO: fix panic in zen. - builtin.Os.freestanding, builtin.Os.zen, builtin.Os.uefi => { + builtin.Os.freestanding, builtin.Os.zen => { while (true) {} }, + builtin.Os.uefi => { + // TODO look into using the debug info and logging helpful messages + std.os.abort(); + }, else => { const first_trace_addr = @ptrToInt(@returnAddress()); std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); From c29cae76b0fefe4af53d3f4fe72f8e3e95c93809 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Wed, 26 Dec 2018 22:44:13 -0200 Subject: [PATCH 077/218] tests: add FreeBSD to the test matrix --- test/tests.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/tests.zig b/test/tests.zig index 1ca06b4b34..866955f707 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -38,6 +38,11 @@ const test_targets = []TestTarget{ .arch = builtin.Arch.x86_64, .environ = builtin.Environ.unknown, }, + TestTarget{ + .os = builtin.Os.freebsd, + .arch = builtin.Arch.x86_64, + .environ = builtin.Environ.unknown, + }, TestTarget{ .os = builtin.Os.windows, .arch = builtin.Arch.x86_64, From aaef6259c32ff43be912c31f70e005170ee86efd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Dec 2018 20:44:06 -0500 Subject: [PATCH 078/218] allow not having libc include paths and doing @cImport --- src/analyze.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 04d957b626..3e2e5abc74 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4590,8 +4590,7 @@ static Buf *get_posix_libc_include_path(void) { void find_libc_include_path(CodeGen *g) { if (g->libc_include_dir == nullptr) { if (!g->is_native_target) { - fprintf(stderr, "Unable to determine libc include path. --libc-include-dir"); - exit(1); + return; } if (g->zig_target.os == OsWindows) { From 64061cc1bfb8e925d20f5824aa178b61eb2e5f11 Mon Sep 17 00:00:00 2001 From: alexander Date: Thu, 27 Dec 2018 13:46:32 -0600 Subject: [PATCH 079/218] Test cases for compiler error and working behavior for switching on booleans --- test/cases/switch.zig | 37 +++++++++++++++++++++++++++++++++++++ test/compile_errors.zig | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/test/cases/switch.zig b/test/cases/switch.zig index d5258f0bb1..1162fdd4b2 100644 --- a/test/cases/switch.zig +++ b/test/cases/switch.zig @@ -232,3 +232,40 @@ test "capture value of switch with all unreachable prongs" { }; assert(x == 1); } + +test "switching on booleans" { + testSwitchOnBools(); + comptime testSwitchOnBools(); +} + +fn testSwitchOnBools() void { + assert(testSwitchOnBoolsTrueAndFalse(true) == false); + assert(testSwitchOnBoolsTrueAndFalse(false) == true); + + assert(testSwitchOnBoolsTrueWithElse(true) == false); + assert(testSwitchOnBoolsTrueWithElse(false) == true); + + assert(testSwitchOnBoolsFalseWithElse(true) == false); + assert(testSwitchOnBoolsFalseWithElse(false) == true); +} + +fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { + return switch (x) { + true => false, + false => true, + }; +} + +fn testSwitchOnBoolsTrueWithElse(x: bool) bool { + return switch (x) { + true => false, + else => true, + }; +} + +fn testSwitchOnBoolsFalseWithElse(x: bool) bool { + return switch (x) { + false => true, + else => false, + }; +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ee3741ee6b..880a96a322 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,44 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "duplicate boolean switch value", + \\comptime { + \\ const x = switch (true) { + \\ true => false, + \\ false => true, + \\ true => false, + \\ }; + \\} + \\comptime { + \\ const x = switch (true) { + \\ false => true, + \\ true => false, + \\ false => true, + \\ }; + \\} + , + ".tmp_source.zig:5:9: error: duplicate switch value", + ".tmp_source.zig:12:9: error: duplicate switch value", + ); + + cases.add( + "missing boolean switch value", + \\comptime { + \\ const x = switch (true) { + \\ true => false, + \\ }; + \\} + \\comptime { + \\ const x = switch (true) { + \\ false => true, + \\ }; + \\} + , + ".tmp_source.zig:2:15: error: switch must handle all possibilities", + ".tmp_source.zig:7:15: error: switch must handle all possibilities", + ); + cases.add( "reading past end of pointer casted array", \\comptime { From 4ff23b668a339b28dceba3d6bc584009aacd1678 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 28 Dec 2018 11:38:58 -0200 Subject: [PATCH 080/218] tests: remove freebsd from the test matrix - Manually add all the native tests to CI manifest. --- .builds/freebsd.yml | 30 ++++++++++++++++++++++++++++++ test/tests.zig | 5 ----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index db1ddb337a..f337bae233 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -14,6 +14,36 @@ tasks: - test: | cd zig/build bin/zig test ../test/behavior.zig + bin/zig test ../std/special/compiler_rt/index.zig + bin/zig test ../std/index.zig + + bin/zig test ../test/behavior.zig --library c + bin/zig test ../std/special/compiler_rt/index.zig --library c + bin/zig test ../std/index.zig --library c + + bin/zig test ../test/behavior.zig --release-fast + bin/zig test ../std/special/compiler_rt/index.zig --release-fast + bin/zig test ../std/index.zig --release-fast + + bin/zig test ../test/behavior.zig --release-fast --library c + bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c + bin/zig test ../std/index.zig --release-fast --library c + + bin/zig test ../test/behavior.zig --release-small --library c + bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c + bin/zig test ../std/index.zig --release-small --library c + + bin/zig test ../test/behavior.zig --release-small + bin/zig test ../std/special/compiler_rt/index.zig --release-small + bin/zig test ../std/index.zig --release-small + + bin/zig test ../test/behavior.zig --release-safe + bin/zig test ../std/special/compiler_rt/index.zig --release-safe + bin/zig test ../std/index.zig --release-safe + + bin/zig test ../test/behavior.zig --release-safe --library c + bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c + bin/zig test ../std/index.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/test/tests.zig b/test/tests.zig index 866955f707..1ca06b4b34 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -38,11 +38,6 @@ const test_targets = []TestTarget{ .arch = builtin.Arch.x86_64, .environ = builtin.Environ.unknown, }, - TestTarget{ - .os = builtin.Os.freebsd, - .arch = builtin.Arch.x86_64, - .environ = builtin.Environ.unknown, - }, TestTarget{ .os = builtin.Os.windows, .arch = builtin.Arch.x86_64, From 2e08bd6be4a3b472fcaa69f0cb7683b269cdacdd Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 28 Dec 2018 15:36:43 -0200 Subject: [PATCH 081/218] ci: update freebsd manifest --- .builds/freebsd.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index f337bae233..c7d92712b0 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,5 +1,4 @@ -arch: x86_64 -image: freebsd +image: freebsd/latest packages: - cmake - ninja @@ -15,35 +14,27 @@ tasks: cd zig/build bin/zig test ../test/behavior.zig bin/zig test ../std/special/compiler_rt/index.zig - bin/zig test ../std/index.zig bin/zig test ../test/behavior.zig --library c bin/zig test ../std/special/compiler_rt/index.zig --library c - bin/zig test ../std/index.zig --library c bin/zig test ../test/behavior.zig --release-fast bin/zig test ../std/special/compiler_rt/index.zig --release-fast - bin/zig test ../std/index.zig --release-fast bin/zig test ../test/behavior.zig --release-fast --library c bin/zig test ../std/special/compiler_rt/index.zig --release-fast --library c - bin/zig test ../std/index.zig --release-fast --library c bin/zig test ../test/behavior.zig --release-small --library c bin/zig test ../std/special/compiler_rt/index.zig --release-small --library c - bin/zig test ../std/index.zig --release-small --library c bin/zig test ../test/behavior.zig --release-small bin/zig test ../std/special/compiler_rt/index.zig --release-small - bin/zig test ../std/index.zig --release-small bin/zig test ../test/behavior.zig --release-safe bin/zig test ../std/special/compiler_rt/index.zig --release-safe - bin/zig test ../std/index.zig --release-safe bin/zig test ../test/behavior.zig --release-safe --library c bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c - bin/zig test ../std/index.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 From 6df8e4bca73309f2e340dbfa9031f1bb16a73bcc Mon Sep 17 00:00:00 2001 From: alexander Date: Sat, 29 Dec 2018 21:49:31 -0600 Subject: [PATCH 082/218] Add DIFlagStaticMember flag to functions. Prevents LLVM from generating debug info for struct member functions with a pointer as the first parameter as though the first parameter were the implicit "this" pointer from C++. --- src/zig_llvm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index bda8fa0adc..3c01a0954d 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -605,7 +605,7 @@ ZigLLVMDISubprogram *ZigLLVMCreateFunction(ZigLLVMDIBuilder *dibuilder, ZigLLVMD reinterpret_cast(file), lineno, di_sub_type, - is_local_to_unit, is_definition, scope_line, DINode::FlagZero, is_optimized, + is_local_to_unit, is_definition, scope_line, DINode::FlagStaticMember, is_optimized, nullptr, reinterpret_cast(decl_subprogram)); return reinterpret_cast(result); From f6cd68386d76e4a9a489187c47f218b59e1734f3 Mon Sep 17 00:00:00 2001 From: vegecode <39607947+vegecode@users.noreply.github.com> Date: Wed, 2 Jan 2019 15:47:47 -0600 Subject: [PATCH 083/218] @bitreverse intrinsic, part of #767 (#1865) * bitreverse - give bswap behavior * bitreverse, comptime_ints, negative values still not working? * bitreverse working for negative comptime ints * Finished bitreverse test cases * Undo exporting a bigint function. @bitreverse test name includes ampersand * added docs entry for @bitreverse --- doc/langref.html.in | 12 +++++ src/all_types.hpp | 13 ++++++ src/analyze.cpp | 4 ++ src/bigint.cpp | 1 + src/codegen.cpp | 16 +++++++ src/ir.cpp | 98 ++++++++++++++++++++++++++++++++++++++- src/ir_print.cpp | 15 ++++++ test/behavior.zig | 1 + test/cases/bitreverse.zig | 81 ++++++++++++++++++++++++++++++++ 9 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 test/cases/bitreverse.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index 2a2b4003fb..6e03d3ec6d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5316,6 +5316,18 @@ comptime {

{#header_close#} + {#header_open|@bitreverse#} +
{#syntax#}@bitreverse(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} accepts any integer type.

+

+ Reverses the bitpattern of an integer value, including the sign bit if applicable. +

+

+ For example 0b10110110 ({#syntax#}u8 = 182{#endsyntax#}, {#syntax#}i8 = -74{#endsyntax#}) + becomes 0b01101101 ({#syntax#}u8 = 109{#endsyntax#}, {#syntax#}i8 = 109{#endsyntax#}). +

+ {#header_close#} + {#header_open|@byteOffsetOf#}
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}

diff --git a/src/all_types.hpp b/src/all_types.hpp index 2b55f8ee2e..df318729f5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,7 @@ enum BuiltinFnId { BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, BuiltinFnIdBswap, + BuiltinFnIdBitReverse, }; struct BuiltinFnEntry { @@ -1488,6 +1489,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, ZigLLVMFnIdBswap, + ZigLLVMFnIdBitReverse, }; enum AddSubMul { @@ -1520,6 +1522,9 @@ struct ZigLLVMFnKey { struct { uint32_t bit_count; } bswap; + struct { + uint32_t bit_count; + } bit_reverse; } data; }; @@ -2162,6 +2167,7 @@ enum IrInstructionId { IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, IrInstructionIdBswap, + IrInstructionIdBitReverse, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3262,6 +3268,13 @@ struct IrInstructionBswap { IrInstruction *op; }; +struct IrInstructionBitReverse { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 0f2b8e48cc..b9794114a0 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6121,6 +6121,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; case ZigLLVMFnIdBswap: return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; + case ZigLLVMFnIdBitReverse: + return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6141,6 +6143,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.pop_count.bit_count == b.data.pop_count.bit_count; case ZigLLVMFnIdBswap: return a.data.bswap.bit_count == b.data.bswap.bit_count; + case ZigLLVMFnIdBitReverse: + return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/bigint.cpp b/src/bigint.cpp index 8a8d028e82..7299f2379c 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) { bigint_add(x, ©, &one); } + diff --git a/src/codegen.cpp b/src/codegen.cpp index 6a0596f62f..db8a5f7bb2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdBswap; key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBitReverse) { + fn_name = "bitreverse"; + n_args = 1; + key.id = ZigLLVMFnIdBitReverse; + key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); } +static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBitReverse); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); } zig_unreachable(); } @@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); + create_builtin_fn(g, BuiltinFnIdBitReverse, "bitreverse", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index b1429ae8ac..dac5403550 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { return IrInstructionIdBswap; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) { + return IrInstructionIdBitReverse; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } +static IrInstruction *ir_build_bit_reverse(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBitReverse *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo Buf *name = fn_ref_expr->data.symbol_expr.symbol; auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - if (!entry) { + if (!entry) { // new built in not found add_node_error(irb->codegen, node, buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); return irb->codegen->invalid_instruction; @@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBitReverse: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -21115,6 +21145,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction return result; } +static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t num_bits = int_type->data.integral.bit_count; + size_t buf_size = (num_bits + 7) / 8; + uint8_t *comptime_buf = allocate_nonzero(buf_size); + uint8_t *result_buf = allocate_nonzero(buf_size); + memset(comptime_buf,0,buf_size); + memset(result_buf,0,buf_size); + + bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); + + size_t bit_i = 0; + size_t bit_rev_i = num_bits - 1; + for (; bit_i < num_bits; bit_i++, bit_rev_i--) { + if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { + result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); + } + } + + bigint_read_twos_complement(&result->value.data.x_bigint, + result_buf, + int_type->data.integral.bit_count, + ira->codegen->is_big_endian, + int_type->data.integral.is_signed); + + return result; + } + + IrInstruction *result = ir_build_bit_reverse(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; @@ -21453,6 +21546,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_analyze_instruction_bit_reverse(ira, (IrInstructionBitReverse *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21675,6 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: case IrInstructionIdBswap: + case IrInstructionIdBitReverse: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e09b0073eb..b5099db86a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bit_reverse(IrPrint *irp, IrInstructionBitReverse *instruction) { + fprintf(irp->f, "@bitreverse("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBswap: ir_print_bswap(irp, (IrInstructionBswap *)instruction); break; + case IrInstructionIdBitReverse: + ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/test/behavior.zig b/test/behavior.zig index 8090359772..10cd08dad7 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -9,6 +9,7 @@ comptime { _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); _ = @import("cases/bswap.zig"); + _ = @import("cases/bitreverse.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig new file mode 100644 index 0000000000..3721e68a94 --- /dev/null +++ b/test/cases/bitreverse.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const assert = std.debug.assert; +const minInt = std.math.minInt; + +test "@bitreverse" { + comptime testBitReverse(); + testBitReverse(); +} + +fn testBitReverse() void { + // using comptime_ints, unsigned + assert(@bitreverse(u0, 0) == 0); + assert(@bitreverse(u5, 0x12) == 0x9); + assert(@bitreverse(u8, 0x12) == 0x48); + assert(@bitreverse(u16, 0x1234) == 0x2c48); + assert(@bitreverse(u24, 0x123456) == 0x6a2c48); + assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using runtime uints, unsigned + var num0: u0 = 0; + assert(@bitreverse(u0, num0) == 0); + var num5: u5 = 0x12; + assert(@bitreverse(u5, num5) == 0x9); + var num8: u8 = 0x12; + assert(@bitreverse(u8, num8) == 0x48); + var num16: u16 = 0x1234; + assert(@bitreverse(u16, num16) == 0x2c48); + var num24: u24 = 0x123456; + assert(@bitreverse(u24, num24) == 0x6a2c48); + var num32: u32 = 0x12345678; + assert(@bitreverse(u32, num32) == 0x1e6a2c48); + var num40: u40 = 0x123456789a; + assert(@bitreverse(u40, num40) == 0x591e6a2c48); + var num48: u48 = 0x123456789abc; + assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); + var num56: u56 = 0x123456789abcde; + assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + var num64: u64 = 0x123456789abcdef1; + assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + var num128: u128 = 0x123456789abcdef11121314151617181; + assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using comptime_ints, signed, positive + assert(@bitreverse(i0, 0) == 0); + assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); + assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); + assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); + assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); + assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); + assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); + assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); + assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); + assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); + + // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. + var neg5: i5 = minInt(i5) + 1; + assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + var neg8: i8 = -18; + assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + var neg16: i16 = -32694; + assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + var neg24: i24 = -6773785; + assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + var neg32: i32 = -16773785; + assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + var neg40: i40 = minInt(i40) + 12345; + assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + var neg48: i48 = minInt(i48) + 12345; + assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + var neg56: i56 = minInt(i56) + 12345; + assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + var neg64: i64 = minInt(i64) + 12345; + assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + var neg128: i128 = minInt(i128) + 12345; + assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); +} From 1e781a30f63acc597129a8f0c4fee7390a96192b Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 4 Jan 2019 14:19:21 -0200 Subject: [PATCH 084/218] freebsd: add clock const definitions --- std/os/freebsd/index.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 603265b956..c122c2d7e1 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -26,6 +26,21 @@ 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; From 4d9547ff2e9377abeb87b53e30580cf1a561f9ce Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 4 Jan 2019 14:42:45 -0200 Subject: [PATCH 085/218] freebsd: implement clock related functions - clock_gettime - clock_getres --- std/c/freebsd.zig | 2 ++ std/os/freebsd/index.zig | 8 ++++++++ std/os/time.zig | 8 ++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index eae5516db3..4d5c3810e8 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -22,6 +22,8 @@ pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int; pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; pub extern "c" fn setuid(uid: c_uint) c_int; pub extern "c" fn kill(pid: c_int, sig: c_int) c_int; +pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; +pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index c122c2d7e1..9bb683f69e 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -714,6 +714,14 @@ 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 clock_gettime(clk_id, tp); +} + pub fn setuid(uid: u32) usize { return errnoWrap(c.setuid(uid)); } diff --git a/std/os/time.zig b/std/os/time.zig index c3588838bc..42f32f8fee 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -61,7 +61,7 @@ pub fn timestamp() u64 { /// Get the posix timestamp, UTC, in milliseconds pub const milliTimestamp = switch (builtin.os) { Os.windows => milliTimestampWindows, - Os.linux => milliTimestampPosix, + Os.linux, Os.freebsd => milliTimestampPosix, Os.macosx, Os.ios => milliTimestampDarwin, else => @compileError("Unsupported OS"), }; @@ -179,7 +179,7 @@ pub const Timer = struct { debug.assert(err != windows.FALSE); self.start_time = @intCast(u64, start_time); }, - Os.linux => { + Os.linux, Os.freebsd => { //On Linux, seccomp can do arbitrary things to our ability to call // syscalls, including return any errno value it wants and // inconsistently throwing errors. Since we can't account for @@ -215,7 +215,7 @@ pub const Timer = struct { var clock = clockNative() - self.start_time; return switch (builtin.os) { Os.windows => @divFloor(clock * ns_per_s, self.frequency), - Os.linux => clock, + Os.linux, Os.freebsd => clock, Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), else => @compileError("Unsupported OS"), }; @@ -236,7 +236,7 @@ pub const Timer = struct { const clockNative = switch (builtin.os) { Os.windows => clockWindows, - Os.linux => clockLinux, + Os.linux, Os.freebsd => clockLinux, Os.macosx, Os.ios => clockDarwin, else => @compileError("Unsupported OS"), }; From 5c2a1055a03d4ef9e4d292afe8b934cb6a7afa11 Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Fri, 4 Jan 2019 16:17:46 -0200 Subject: [PATCH 086/218] freebsd: add sockaddr structs --- std/c/freebsd.zig | 25 +++++++++++++++++++++++++ std/os/freebsd/index.zig | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 4d5c3810e8..2f2f4c0a1b 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -93,3 +93,28 @@ pub const dirent = extern struct { d_pad1: u16, d_name: [256]u8, }; + +pub const in_port_t = u16; +pub const sa_family_t = u16; + +pub const sockaddr = extern union { + in: sockaddr_in, + in6: sockaddr_in6, +}; + +pub const sockaddr_in = extern struct { + len: u8, + family: sa_family_t, + port: in_port_t, + addr: [16]u8, + zero: [8]u8, +}; + +pub const sockaddr_in6 = extern struct { + len: u8, + family: sa_family_t, + port: in_port_t, + flowinfo: u32, + addr: [16]u8, + scope_id: u32, +}; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 9bb683f69e..c333ef2ac4 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -525,6 +525,10 @@ 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); } From 1f08be4d7fdf08bda66312ab4b2e401de378083e Mon Sep 17 00:00:00 2001 From: vegecode <39607947+vegecode@users.noreply.github.com> Date: Fri, 4 Jan 2019 16:34:21 -0600 Subject: [PATCH 087/218] Mark comptime int hardcoded address pointee as a run time variable #1171 (#1868) * Mark comptime int hardcoded address as a run time variable #1171 * test case for dereferencing hardcoded address intToPtr --- src/ir.cpp | 1 + test/cases/inttoptr.zig | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index dac5403550..400b07368b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20363,6 +20363,7 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru IrInstruction *result = ir_const(ira, &instruction->base, dest_type); result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); return result; } diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig index 6695352383..ba3cc52f09 100644 --- a/test/cases/inttoptr.zig +++ b/test/cases/inttoptr.zig @@ -11,3 +11,17 @@ fn randomAddressToFunction() void { var addr: usize = 0xdeadbeef; var ptr = @intToPtr(fn () void, addr); } + +test "mutate through ptr initialized with constant intToPtr value" { + forceCompilerAnalyzeBranchHardCodedPtrDereference(false); +} + +fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { + const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); + if (x) { + hardCodedP.* = hardCodedP.* | 10; + } else { + return; + } +} + From 5f26d1dddbe9004429adca6e55d3344ca58062ae Mon Sep 17 00:00:00 2001 From: Marcio Date: Sat, 5 Jan 2019 18:34:47 +0000 Subject: [PATCH 088/218] freebsd: fix wrong call to clock_getres (#1871) Reported-by: daurnimator --- std/os/freebsd/index.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index c333ef2ac4..a3ab5e7749 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -723,7 +723,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { } pub fn clock_getres(clk_id: i32, tp: *timespec) usize { - return clock_gettime(clk_id, tp); + return errnoWrap(c.clock_getres(clk_id, tp)); } pub fn setuid(uid: u32) usize { From db928915878c64f9e5c479739bd768bd4ac0b912 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:48:31 +0100 Subject: [PATCH 089/218] Respect the type system instead of ConstExprValue when getting field --- src/ir.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 400b07368b..d74bef2424 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14577,8 +14577,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_instruction; - ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type, + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, PtrLenSingle, align_bytes, (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), (uint32_t)host_int_bytes_for_result_type); From e410b1f915974fe3daeebae324e8c4e4b42090dd Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:49:24 +0100 Subject: [PATCH 090/218] Implemented buf_read_value_bytes for ZigTypeIdArray * Only for x_array.special == ConstArraySpecialNone --- src/ir.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index d74bef2424..2353bb1086 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20179,8 +20179,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } - case ZigTypeIdArray: - zig_panic("TODO buf_read_value_bytes array type"); + case ZigTypeIdArray: { + uint64_t elem_size = type_size(ira->codegen, val->type->data.array.child_type); + size_t len = val->type->data.array.len; + + switch (val->data.x_array.special) { + case ConstArraySpecialNone: + val->data.x_array.data.s_none.elements = create_const_vals(len); + for (size_t i = 0; i < len; i++) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = val->type->data.array.child_type; + if ((err = buf_read_value_bytes(ira, source_node, buf + (elem_size * i), elem))) + return err; + } + break; + case ConstArraySpecialUndef: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); + case ConstArraySpecialBuf: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); + } + + return ErrorNone; + } case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { From 55e95daf543a27961fe9ca7a998d3cbd25d2973b Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:53:34 +0100 Subject: [PATCH 091/218] Fixed issue where TypeInfo would use types from a prev CodeGen instance When doing multible codegen passes (such as building compiler_rt and then something else) the TypeInfo cache code would point to types from the prev code gen (such as the prev 'bool' type), giving us errors like "expected type 'bool', but found type 'bool'" This disabling of caching might have a performance hit, but correctness is better than speed, so let's have this for now, until someone optimizes this correctly (probably in stage2) --- src/ir.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 2353bb1086..4e401b7249 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16882,16 +16882,12 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { Error err; - static ConstExprValue *type_info_var = nullptr; // TODO oops this global variable made it past code review - static ZigType *type_info_type = nullptr; // TODO oops this global variable made it past code review - if (type_info_var == nullptr) { - type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); - assert(type_info_var->type->id == ZigTypeIdMetaType); + ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); // TODO oops this global variable made it past code review + assert(type_info_var->type->id == ZigTypeIdMetaType); + assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - type_info_type = type_info_var->data.x_type; - assert(type_info_type->id == ZigTypeIdUnion); - } + ZigType *type_info_type = type_info_var->data.x_type; // TODO oops this global variable made it past code review + assert(type_info_type->id == ZigTypeIdUnion); if (type_name == nullptr && root == nullptr) return type_info_type; From 97702988d1783db6840c642809a41d8f176bb500 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:58:00 +0100 Subject: [PATCH 092/218] Added test case --- test/cases/ptrcast.zig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig index 6f0e6e5946..54c3dda849 100644 --- a/test/cases/ptrcast.zig +++ b/test/cases/ptrcast.zig @@ -34,3 +34,19 @@ fn testReinterpretBytesAsExternStruct() void { var val = ptr.c; assertOrPanic(val == 5); } + +test "reinterpret struct field at comptime" { + const numLittle = comptime Bytes.init(0x12345678); + assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); +} + +const Bytes = struct { + bytes: [4]u8, + + pub fn init(v: u32) Bytes { + var res: Bytes = undefined; + @ptrCast(*align(1) u32, &res.bytes).* = v; + + return res; + } +}; From da08525bb31c3608667254132b65e409f5869a03 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 18:02:00 +0100 Subject: [PATCH 093/218] Removed oops comments --- src/ir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 4e401b7249..531b705538 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16882,11 +16882,11 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { Error err; - ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); // TODO oops this global variable made it past code review + ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); assert(type_info_var->type->id == ZigTypeIdMetaType); assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - ZigType *type_info_type = type_info_var->data.x_type; // TODO oops this global variable made it past code review + ZigType *type_info_type = type_info_var->data.x_type; assert(type_info_type->id == ZigTypeIdUnion); if (type_name == nullptr && root == nullptr) From aa65b946711d6f51050977880f64a70f13637e45 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 8 Jan 2019 10:57:39 -0500 Subject: [PATCH 094/218] fix debug info for function pointers found when testing against LLVM 8 see https://bugs.llvm.org/show_bug.cgi?id=40198 --- src/all_types.hpp | 1 + src/analyze.cpp | 5 ++++- src/codegen.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index df318729f5..91b24e3110 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1166,6 +1166,7 @@ struct ZigTypeFn { FnGenParamInfo *gen_param_info; LLVMTypeRef raw_type_ref; + ZigLLVMDIType *raw_di_type; ZigType *bound_fn_parent; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index b9794114a0..af65838eae 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1220,7 +1220,10 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); - fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type, + LLVMStoreSizeOfType(g->target_data_ref, fn_type->type_ref), + LLVMABIAlignmentOfType(g->target_data_ref, fn_type->type_ref), ""); } g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index db8a5f7bb2..0c979386e3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -649,7 +649,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, - fn_table_entry->type_entry->di_type, is_internal_linkage, + fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage, is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); From 4d5d0d3adad09e9ce34d281327c424de6402fcdb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 8 Jan 2019 14:40:56 -0500 Subject: [PATCH 095/218] `@typeInfo`: more correct return type info --- src/ir.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 531b705538..6e6c46885b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17100,12 +17100,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ensure_field_index(fn_def_val->type, "return_type", 7); fn_def_fields[7].special = ConstValSpecialStatic; fn_def_fields[7].type = ira->codegen->builtin_types.entry_type; - if (fn_entry->src_implicit_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type; - else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type; - else - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; + fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; // arg_names: [][] const u8 ensure_field_index(fn_def_val->type, "arg_names", 8); size_t fn_arg_count = fn_entry->variable_list.length; From 5864d92b4049e6d60a21a3f22220464808dd0518 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 9 Jan 2019 10:43:48 -0500 Subject: [PATCH 096/218] when rendering llvm const values, ensure the types align the representation of the const expr val in zig, and the type that we tell LLVM it is. --- src/analyze.cpp | 21 +++++++- src/analyze.hpp | 3 ++ src/codegen.cpp | 8 ++++ src/ir.cpp | 125 ++++++++++++++++++++++++++---------------------- src/ir.hpp | 5 +- 5 files changed, 102 insertions(+), 60 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index af65838eae..00eb38de9e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5757,7 +5757,8 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy case ConstPtrSpecialRef: case ConstPtrSpecialBaseStruct: buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: if (const_val->data.x_ptr.data.base_array.is_cstr) { @@ -5765,7 +5766,8 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy return; } else { buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; } case ConstPtrSpecialHardCodedAddr: @@ -6599,3 +6601,18 @@ uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *f LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(struct_type->type_ref, field->gen_index); return LLVMStoreSizeOfType(g->target_data_ref, field_type); } + +Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *const_val, ZigType *wanted_type) +{ + ConstExprValue ptr_val = {}; + ptr_val.special = ConstValSpecialStatic; + ptr_val.type = get_pointer_to_type(codegen, wanted_type, true); + ptr_val.data.x_ptr.mut = ConstPtrMutComptimeConst; + ptr_val.data.x_ptr.special = ConstPtrSpecialRef; + ptr_val.data.x_ptr.data.ref.pointee = const_val; + if (const_ptr_pointee(ira, codegen, &ptr_val, source_node) == nullptr) + return ErrorSemanticAnalyzeFail; + + return ErrorNone; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index b506b533ca..efbc065a63 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -222,4 +222,7 @@ enum ReqCompTime { }; ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); +Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *const_val, ZigType *wanted_type); + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 0c979386e3..47f2aa103f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5626,6 +5626,8 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con } static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { + Error err; + ZigType *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -5769,6 +5771,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c } ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; assert(field_val->type != nullptr); + if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, + type_struct_field->type_entry))) + { + zig_unreachable(); + } + LLVMValueRef val = gen_const_val(g, field_val, ""); fields[type_struct_field->gen_index] = val; make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); diff --git a/src/ir.cpp b/src/ir.cpp index 6e6c46885b..c651f30dd5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -159,9 +159,9 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val); +static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); -static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, +static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); @@ -7391,35 +7391,46 @@ static ErrorMsg *ir_add_error_node(IrAnalyze *ira, AstNode *source_node, Buf *ms return exec_add_error_node(ira->codegen, ira->new_irb.exec, source_node, msg); } +static ErrorMsg *opt_ir_add_error_node(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, Buf *msg) { + if (ira != nullptr) + return exec_add_error_node(codegen, ira->new_irb.exec, source_node, msg); + else + return add_node_error(codegen, source_node, msg); +} + static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { return ir_add_error_node(ira, source_instruction->source_node, msg); } // This function takes a comptime ptr and makes the child const value conform to the type // described by the pointer. -static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, AstNode *source_node, ConstExprValue *ptr_val) { +static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *ptr_val) +{ Error err; assert(ptr_val->type->id == ZigTypeIdPointer); ConstExprValue tmp = {}; tmp.special = ConstValSpecialStatic; tmp.type = ptr_val->type->data.pointer.child_type; - if ((err = ir_read_const_ptr(ira, source_node, &tmp, ptr_val))) + if ((err = ir_read_const_ptr(ira, codegen, source_node, &tmp, ptr_val))) return err; - ConstExprValue *child_val = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + ConstExprValue *child_val = const_ptr_pointee_unchecked(codegen, ptr_val); copy_const_val(child_val, &tmp, false); return ErrorNone; } -static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) { +ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, + AstNode *source_node) +{ Error err; - ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val); + ConstExprValue *val = const_ptr_pointee_unchecked(codegen, const_val); assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { - if ((err = eval_comptime_ptr_reinterpret(ira, source_node, const_val))) + if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val))) return nullptr; - return const_ptr_pointee_unchecked(ira->codegen, const_val); + return const_ptr_pointee_unchecked(codegen, const_val); } return val; } @@ -9461,7 +9472,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { - ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -9497,7 +9508,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { - ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -10456,7 +10467,7 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou return ira->codegen->invalid_instruction; assert(val->type->id == ZigTypeIdPointer); - ConstExprValue *pointee = ir_const_ptr_pointee(ira, val, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -11025,7 +11036,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); - if ((err = ir_read_const_ptr(ira, source_instruction->source_node, &result->value, + if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, &ptr->value))) { return ira->codegen->invalid_instruction; @@ -13730,21 +13741,21 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC // out_val->type must be the type to read the pointer as // if the type is different than the actual type then it does a comptime byte reinterpretation -static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, +static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val) { Error err; assert(out_val->type != nullptr); - ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + ConstExprValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val); - if ((err = type_resolve(ira->codegen, pointee->type, ResolveStatusSizeKnown))) + if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - if ((err = type_resolve(ira->codegen, out_val->type, ResolveStatusSizeKnown))) + if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - size_t src_size = type_size(ira->codegen, pointee->type); - size_t dst_size = type_size(ira->codegen, out_val->type); + size_t src_size = type_size(codegen, pointee->type); + size_t dst_size = type_size(codegen, out_val->type); if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); @@ -13754,8 +13765,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, if (dst_size <= src_size) { Buf buf = BUF_INIT; buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; return ErrorNone; } @@ -13764,7 +13775,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, case ConstPtrSpecialInvalid: zig_unreachable(); case ConstPtrSpecialRef: { - ir_add_error_node(ira, source_node, + opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; @@ -13778,7 +13789,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { - ir_add_error_node(ira, source_node, + opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; @@ -13788,9 +13799,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, buf_resize(&buf, elem_count * elem_size); for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } - if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; return ErrorNone; } @@ -14227,7 +14238,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct array_type = array_type->data.pointer.child_type; ptr_type = ptr_type->data.pointer.child_type; if (orig_array_ptr_val->special != ConstValSpecialRuntime) { - orig_array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val, + orig_array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, elem_ptr_instruction->base.source_node); if (orig_array_ptr_val == nullptr) return ira->codegen->invalid_instruction; @@ -14271,7 +14282,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *args_val = ir_const_ptr_pointee(ira, ptr_val, elem_ptr_instruction->base.source_node); + ConstExprValue *args_val = const_ptr_pointee(ira, ira->codegen, ptr_val, elem_ptr_instruction->base.source_node); if (args_val == nullptr) return ira->codegen->invalid_instruction; size_t start = args_val->data.x_arg_tuple.start_index; @@ -14353,7 +14364,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == ZigTypeIdArray)) { - ConstExprValue *array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val, + ConstExprValue *array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, elem_ptr_instruction->base.source_node); if (array_ptr_val == nullptr) return ira->codegen->invalid_instruction; @@ -14572,7 +14583,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *struct_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node); + ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (struct_val == nullptr) return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) @@ -14614,7 +14625,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *union_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node); + ConstExprValue *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (union_val == nullptr) return ira->codegen->invalid_instruction; if (type_is_invalid(union_val->type)) @@ -14811,7 +14822,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node); + ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); if (child_val == nullptr) return ira->codegen->invalid_instruction; @@ -14837,7 +14848,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node); + ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); if (child_val == nullptr) return ira->codegen->invalid_instruction; ZigType *child_type = child_val->data.x_type; @@ -15112,7 +15123,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (!container_ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *namespace_val = ir_const_ptr_pointee(ira, container_ptr_val, + 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; @@ -15187,7 +15198,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc } if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { if (instr_is_comptime(casted_value)) { - ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, store_ptr_instruction->base.source_node); + ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node); if (dest_val == nullptr) return ira->codegen->invalid_instruction; if (dest_val->special != ConstValSpecialRuntime) { @@ -15735,7 +15746,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) return ira->codegen->invalid_instruction; - ConstExprValue *maybe_val = ir_const_ptr_pointee(ira, val, unwrap_maybe_instruction->base.source_node); + ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node); if (maybe_val == nullptr) return ira->codegen->invalid_instruction; @@ -16032,7 +16043,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type; ConstExprValue *pointee_val = nullptr; if (instr_is_comptime(target_value_ptr)) { - pointee_val = ir_const_ptr_pointee(ira, &target_value_ptr->value, target_value_ptr->source_node); + pointee_val = const_ptr_pointee(ira, ira->codegen, &target_value_ptr->value, target_value_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; @@ -16167,7 +16178,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru if (!target_value_ptr) return ira->codegen->invalid_instruction; - ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, target_val_ptr, instruction->base.source_node); + ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, target_val_ptr, instruction->base.source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; @@ -18882,18 +18893,18 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction if (array_type->id == ZigTypeIdPointer) { ZigType *child_array_type = array_type->data.pointer.child_type; assert(child_array_type->id == ZigTypeIdArray); - parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + parent_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_instruction; - array_val = ir_const_ptr_pointee(ira, parent_ptr, instruction->base.source_node); + array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.source_node); if (array_val == nullptr) return ira->codegen->invalid_instruction; rel_end = child_array_type->data.array.len; abs_offset = 0; } else { - array_val = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + array_val = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (array_val == nullptr) return ira->codegen->invalid_instruction; rel_end = array_type->data.array.len; @@ -18902,7 +18913,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction } } else if (array_type->id == ZigTypeIdPointer) { assert(array_type->data.pointer.ptr_len == PtrLenUnknown); - parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + parent_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_instruction; @@ -18942,7 +18953,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction zig_panic("TODO slice of ptr cast from function"); } } else if (is_slice(array_type)) { - ConstExprValue *slice_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (slice_ptr == nullptr) return ira->codegen->invalid_instruction; @@ -19351,7 +19362,7 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr { BigInt *op1_bigint = &casted_op1->value.data.x_bigint; BigInt *op2_bigint = &casted_op2->value.data.x_bigint; - ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, &casted_result_ptr->value, casted_result_ptr->source_node); + ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, &casted_result_ptr->value, casted_result_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; BigInt *dest_bigint = &pointee_val->data.x_bigint; @@ -19450,7 +19461,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { @@ -19502,7 +19513,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { @@ -20132,7 +20143,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } -static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { +static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { Error err; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { @@ -20156,22 +20167,22 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t return ErrorNone; case ZigTypeIdInt: bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - ira->codegen->is_big_endian, val->type->data.integral.is_signed); + codegen->is_big_endian, val->type->data.integral.is_signed); return ErrorNone; case ZigTypeIdFloat: - float_read_ieee597(val, buf, ira->codegen->is_big_endian); + float_read_ieee597(val, buf, codegen->is_big_endian); return ErrorNone; case ZigTypeIdPointer: { val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; BigInt bn; - bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count, - ira->codegen->is_big_endian, false); + bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, + codegen->is_big_endian, false); val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } case ZigTypeIdArray: { - uint64_t elem_size = type_size(ira->codegen, val->type->data.array.child_type); + uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); size_t len = val->type->data.array.len; switch (val->data.x_array.special) { @@ -20181,7 +20192,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; elem->special = ConstValSpecialStatic; elem->type = val->type->data.array.child_type; - if ((err = buf_read_value_bytes(ira, source_node, buf + (elem_size * i), elem))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) return err; } break; @@ -20196,10 +20207,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { - ErrorMsg *msg = ir_add_error_node(ira, source_node, + ErrorMsg *msg = opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", buf_ptr(&val->type->name))); - add_error_note(ira->codegen, msg, val->type->data.structure.decl_node, + add_error_note(codegen, msg, val->type->data.structure.decl_node, buf_sprintf("declared here")); return ErrorSemanticAnalyzeFail; } @@ -20213,10 +20224,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t field_val->type = type_field->type_entry; if (type_field->gen_index == SIZE_MAX) continue; - size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref, + size_t offset = LLVMOffsetOfElement(codegen->target_data_ref, val->type->type_ref, type_field->gen_index); uint8_t *new_buf = buf + offset; - if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, new_buf, field_val))) return err; } return ErrorNone; @@ -20327,7 +20338,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value))) + if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value))) return ira->codegen->invalid_instruction; return result; } diff --git a/src/ir.hpp b/src/ir.hpp index b298750dec..7af1d7f52b 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -22,6 +22,9 @@ ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_ ZigType *expected_type, AstNode *expected_type_source_node); bool ir_has_side_effects(IrInstruction *instruction); -ConstExprValue *const_ptr_pointee(CodeGen *codegen, ConstExprValue *const_val); + +struct IrAnalyze; +ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, + AstNode *source_node); #endif From b61bce254cc5c7075e2fb722e7deb0085eebb65e Mon Sep 17 00:00:00 2001 From: emekoi Date: Sun, 18 Nov 2018 00:07:37 -0600 Subject: [PATCH 097/218] added mutex for windows --- std/mutex.zig | 135 +++++++++++++++++++++++++----------- std/os/windows/kernel32.zig | 31 +++++++++ 2 files changed, 127 insertions(+), 39 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index e35bd81bc4..25e6a5bd25 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -5,70 +5,125 @@ const AtomicRmwOp = builtin.AtomicRmwOp; const assert = std.debug.assert; const SpinLock = std.SpinLock; const linux = std.os.linux; +const windows = std.os.windows; /// Lock may be held only once. If the same thread /// tries to acquire the same mutex twice, it deadlocks. /// The Linux implementation is based on mutex3 from /// https://www.akkadia.org/drepper/futex.pdf -pub const Mutex = struct { +pub const Mutex = switch(builtin.os) { + builtin.Os.linux => MutexLinux, + builtin.Os.windows => MutexWindows, + else => MutexSpinLock, +}; + +const MutexLinux = struct { /// 0: unlocked /// 1: locked, no waiters /// 2: locked, one or more waiters - linux_lock: @typeOf(linux_lock_init), - - /// TODO better implementation than spin lock - spin_lock: @typeOf(spin_lock_init), - - const linux_lock_init = if (builtin.os == builtin.Os.linux) i32(0) else {}; - const spin_lock_init = if (builtin.os != builtin.Os.linux) SpinLock.init() else {}; + lock: i32, pub const Held = struct { mutex: *Mutex, pub fn release(self: Held) void { - if (builtin.os == builtin.Os.linux) { - const c = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); - if (c != 1) { - _ = @atomicRmw(i32, &self.mutex.linux_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); - const rc = linux.futex_wake(&self.mutex.linux_lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); - switch (linux.getErrno(rc)) { - 0 => {}, - linux.EINVAL => unreachable, - else => unreachable, - } + const c = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); + if (c != 1) { + _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); + const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); + switch (linux.getErrno(rc)) { + 0 => {}, + linux.EINVAL => unreachable, + else => unreachable, } - } else { - SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.spin_lock }); } } }; pub fn init() Mutex { - return Mutex{ - .linux_lock = linux_lock_init, - .spin_lock = spin_lock_init, + return Mutex { + .lock = 0, }; } + pub fn deinit(self: *Mutex) void {} + pub fn acquire(self: *Mutex) Held { - if (builtin.os == builtin.Os.linux) { - var c = @cmpxchgWeak(i32, &self.linux_lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse - return Held{ .mutex = self }; - if (c != 2) - c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); - while (c != 0) { - const rc = linux.futex_wait(&self.linux_lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); - switch (linux.getErrno(rc)) { - 0, linux.EINTR, linux.EAGAIN => {}, - linux.EINVAL => unreachable, - else => unreachable, - } - c = @atomicRmw(i32, &self.linux_lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); + var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse + return Held{ .mutex = self }; + if (c != 2) + c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); + while (c != 0) { + const rc = linux.futex_wait(&self.lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); + switch (linux.getErrno(rc)) { + 0, linux.EINTR, linux.EAGAIN => {}, + linux.EINVAL => unreachable, + else => unreachable, } - } else { - _ = self.spin_lock.acquire(); + c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); } - return Held{ .mutex = self }; + return Held { .mutex = self }; + } +}; + +const MutexWindows = struct { + lock: ?windows.RTL_CRITICAL_SECTION, + + pub const Held = struct { + mutex: *Mutex, + + pub fn release(self: Held) void { + windows.LeaveCriticalSection(&self.mutex.lock); + } + }; + + fn initOsData(self: *MutexWindows) void { + if (self.lock == null) { + windows.InitializeCriticalSection(&self.lock); + } + } + + pub fn init() Mutex { + return Mutex { + .lock = null, + }; + } + + pub fn deinit(self: *Mutex) void { + windows.DeleteCriticalSection(&self.lock); + self.lock = null; + } + + pub fn acquire(self: *Mutex) Held { + self.initOsData(); + windows.EnterCriticalSection(&self.lock); + return Held { .mutex = self }; + } +}; + +const MutexSpinLock = struct { + /// TODO better implementation than spin lock + lock: SpinLock, + + pub const Held = struct { + mutex: *Mutex, + + pub fn release(self: Held) void { + SpinLock.Held.release(SpinLock.Held { .spinlock = &self.mutex.lock }); + } + }; + + pub fn init() Mutex { + return Mutex { + .lock = SpinLock.init(), + }; + } + + pub fn deinit(self: *Mutex) void {} + + pub fn acquire(self: *Mutex) Held { + _ = self.spin_lock.acquire(); + return Held { .mutex = self }; } }; @@ -90,6 +145,8 @@ test "std.Mutex" { var a = &fixed_buffer_allocator.allocator; var mutex = Mutex.init(); + defer mutex.deinit(); + var context = Context{ .mutex = &mutex, .data = 0, diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 202b8bffeb..1691b6523f 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -220,3 +220,34 @@ pub const FOREGROUND_BLUE = 1; pub const FOREGROUND_GREEN = 2; pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; + +pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; + +pub const LIST_ENTRY = extern struct { + Flink: *LIST_ENTRY, + Blink: *LIST_ENTRY, +}; + +pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { + Type: WORD, + CreatorBackTraceIndex: WORD, + CriticalSection: *RTL_CRITICAL_SECTION, + ProcessLocksList: LIST_ENTRY, + EntryCount: DWORD, + ContentionCount: DWORD, + Flags: DWORD, + CreatorBackTraceIndexHigh: WORD, + SpareWORD: WORD, +}; + +pub const RTL_CRITICAL_SECTION = extern struct { + DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, + LockCount: i32, + RecursionCount: i32, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR, +}; From 99f44219bcc0c8c496a4a5ebd5d8be465cb71c07 Mon Sep 17 00:00:00 2001 From: emekoi Date: Sun, 18 Nov 2018 00:27:47 -0600 Subject: [PATCH 098/218] updated structs --- std/mutex.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/mutex.zig b/std/mutex.zig index 25e6a5bd25..125a763479 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -122,7 +122,7 @@ const MutexSpinLock = struct { pub fn deinit(self: *Mutex) void {} pub fn acquire(self: *Mutex) Held { - _ = self.spin_lock.acquire(); + _ = self.lock.acquire(); return Held { .mutex = self }; } }; From aaae2f5705a2dee3a12ea49c1094c217a73bb897 Mon Sep 17 00:00:00 2001 From: emekoi Date: Sun, 18 Nov 2018 01:15:24 -0600 Subject: [PATCH 099/218] switching from EnterCriticalSection to TryEnterCriticalSection --- std/mutex.zig | 2 +- std/os/windows/kernel32.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 125a763479..c0b5d3b002 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -96,7 +96,7 @@ const MutexWindows = struct { pub fn acquire(self: *Mutex) Held { self.initOsData(); - windows.EnterCriticalSection(&self.lock); + while (windows.TryEnterCriticalSection(&self.lock) == 0) {} return Held { .mutex = self }; } }; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 1691b6523f..141039a155 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -222,7 +222,7 @@ pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn TryEnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) BOOL; pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; From 25d7f5b65475d087ee1f046a364f8a9e6cd60135 Mon Sep 17 00:00:00 2001 From: emekoi Date: Sun, 18 Nov 2018 18:32:50 -0600 Subject: [PATCH 100/218] switching back to EnterCriticalSection --- std/mutex.zig | 13 +++++-------- std/os/windows/kernel32.zig | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index c0b5d3b002..01ff891b80 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -77,12 +77,6 @@ const MutexWindows = struct { } }; - fn initOsData(self: *MutexWindows) void { - if (self.lock == null) { - windows.InitializeCriticalSection(&self.lock); - } - } - pub fn init() Mutex { return Mutex { .lock = null, @@ -95,8 +89,11 @@ const MutexWindows = struct { } pub fn acquire(self: *Mutex) Held { - self.initOsData(); - while (windows.TryEnterCriticalSection(&self.lock) == 0) {} + if (self.lock == null) { + windows.InitializeCriticalSection(&self.lock); + } + + windows.EnterCriticalSection(&self.lock); return Held { .mutex = self }; } }; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 141039a155..1691b6523f 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -222,7 +222,7 @@ pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn TryEnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) BOOL; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; From 207fa3849ca61a6b22084d2d173b36f23ec841bd Mon Sep 17 00:00:00 2001 From: emekoi Date: Mon, 19 Nov 2018 13:52:10 -0600 Subject: [PATCH 101/218] moved to InitializeCriticalSection to init --- std/mutex.zig | 174 +++++++++++++++++------------------- std/os/windows/kernel32.zig | 8 +- 2 files changed, 87 insertions(+), 95 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 01ff891b80..9307637253 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -12,116 +12,108 @@ const windows = std.os.windows; /// The Linux implementation is based on mutex3 from /// https://www.akkadia.org/drepper/futex.pdf pub const Mutex = switch(builtin.os) { - builtin.Os.linux => MutexLinux, - builtin.Os.windows => MutexWindows, - else => MutexSpinLock, -}; + builtin.Os.linux => struct { + /// 0: unlocked + /// 1: locked, no waiters + /// 2: locked, one or more waiters + lock: i32, -const MutexLinux = struct { - /// 0: unlocked - /// 1: locked, no waiters - /// 2: locked, one or more waiters - lock: i32, + pub const Held = struct { + mutex: *Mutex, - pub const Held = struct { - mutex: *Mutex, + pub fn release(self: Held) void { + const c = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); + if (c != 1) { + _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); + const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); + switch (linux.getErrno(rc)) { + 0 => {}, + linux.EINVAL => unreachable, + else => unreachable, + } + } + } + }; - pub fn release(self: Held) void { - const c = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Sub, 1, AtomicOrder.Release); - if (c != 1) { - _ = @atomicRmw(i32, &self.mutex.lock, AtomicRmwOp.Xchg, 0, AtomicOrder.Release); - const rc = linux.futex_wake(&self.mutex.lock, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1); + pub fn init() Mutex { + return Mutex { + .lock = 0, + }; + } + + pub fn deinit(self: *Mutex) void {} + + pub fn acquire(self: *Mutex) Held { + var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse + return Held{ .mutex = self }; + if (c != 2) + c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); + while (c != 0) { + const rc = linux.futex_wait(&self.lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); switch (linux.getErrno(rc)) { - 0 => {}, + 0, linux.EINTR, linux.EAGAIN => {}, linux.EINVAL => unreachable, else => unreachable, } + c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); + } + return Held { .mutex = self }; + } + }, + builtin.Os.windows => struct { + lock: ?*windows.RTL_CRITICAL_SECTION, + + pub const Held = struct { + mutex: *Mutex, + + pub fn release(self: Held) void { + windows.LeaveCriticalSection(self.mutex.lock); + } + }; + + pub fn init() Mutex { + var lock: ?*windows.RTL_CRITICAL_SECTION = null; + windows.InitializeCriticalSection(lock); + return Mutex { .lock = lock }; + } + + pub fn deinit(self: *Mutex) void { + if (self.lock != null) { + windows.DeleteCriticalSection(self.lock); + self.lock = null; } } - }; - pub fn init() Mutex { - return Mutex { - .lock = 0, - }; - } + pub fn acquire(self: *Mutex) Held { + windows.EnterCriticalSection(self.lock); + return Held { .mutex = self }; + } + }, + else => struct { + /// TODO better implementation than spin lock + lock: SpinLock, - pub fn deinit(self: *Mutex) void {} + pub const Held = struct { + mutex: *Mutex, - pub fn acquire(self: *Mutex) Held { - var c = @cmpxchgWeak(i32, &self.lock, 0, 1, AtomicOrder.Acquire, AtomicOrder.Monotonic) orelse - return Held{ .mutex = self }; - if (c != 2) - c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); - while (c != 0) { - const rc = linux.futex_wait(&self.lock, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, 2, null); - switch (linux.getErrno(rc)) { - 0, linux.EINTR, linux.EAGAIN => {}, - linux.EINVAL => unreachable, - else => unreachable, + pub fn release(self: Held) void { + SpinLock.Held.release(SpinLock.Held { .spinlock = &self.mutex.lock }); } - c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); - } - return Held { .mutex = self }; - } -}; - -const MutexWindows = struct { - lock: ?windows.RTL_CRITICAL_SECTION, - - pub const Held = struct { - mutex: *Mutex, - - pub fn release(self: Held) void { - windows.LeaveCriticalSection(&self.mutex.lock); - } - }; - - pub fn init() Mutex { - return Mutex { - .lock = null, }; - } - pub fn deinit(self: *Mutex) void { - windows.DeleteCriticalSection(&self.lock); - self.lock = null; - } - - pub fn acquire(self: *Mutex) Held { - if (self.lock == null) { - windows.InitializeCriticalSection(&self.lock); + pub fn init() Mutex { + return Mutex { + .lock = SpinLock.init(), + }; } - windows.EnterCriticalSection(&self.lock); - return Held { .mutex = self }; - } -}; + pub fn deinit(self: *Mutex) void {} -const MutexSpinLock = struct { - /// TODO better implementation than spin lock - lock: SpinLock, - - pub const Held = struct { - mutex: *Mutex, - - pub fn release(self: Held) void { - SpinLock.Held.release(SpinLock.Held { .spinlock = &self.mutex.lock }); + pub fn acquire(self: *Mutex) Held { + _ = self.lock.acquire(); + return Held { .mutex = self }; } - }; - - pub fn init() Mutex { - return Mutex { - .lock = SpinLock.init(), - }; - } - - pub fn deinit(self: *Mutex) void {} - - pub fn acquire(self: *Mutex) Held { - _ = self.lock.acquire(); - return Held { .mutex = self }; - } + }, }; const Context = struct { diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 1691b6523f..e34092ad51 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -221,10 +221,10 @@ pub const FOREGROUND_GREEN = 2; pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; -pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *?RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; pub const LIST_ENTRY = extern struct { Flink: *LIST_ENTRY, From bb31695fbfbf7c808dc3fd8c3cfc0b654ed15e5e Mon Sep 17 00:00:00 2001 From: emekoi Date: Mon, 26 Nov 2018 21:07:01 -0600 Subject: [PATCH 102/218] fixed mutex on windows --- std/mutex.zig | 54 +++++++++++++++++++++++++++---------- std/os/windows/index.zig | 1 + std/os/windows/kernel32.zig | 24 ++++++++++++----- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 9307637253..45336f353e 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -61,31 +61,57 @@ pub const Mutex = switch(builtin.os) { } }, builtin.Os.windows => struct { - lock: ?*windows.RTL_CRITICAL_SECTION, + + lock: ?windows.CRITICAL_SECTION, + init_once: windows.PINIT_ONCE, pub const Held = struct { mutex: *Mutex, pub fn release(self: Held) void { - windows.LeaveCriticalSection(self.mutex.lock); + if (self.mutex.lock) |*lock| { + windows.LeaveCriticalSection(lock); + } } }; pub fn init() Mutex { - var lock: ?*windows.RTL_CRITICAL_SECTION = null; - windows.InitializeCriticalSection(lock); - return Mutex { .lock = lock }; + return Mutex { + .lock = null, + .init_once = undefined, + }; + } + + extern fn initCriticalSection(InitOnce: *windows.PINIT_ONCE, Parameter: ?windows.PVOID, Context: ?*windows.PVOID) windows.BOOL { + if (Context) |ctx| { + var mutex = @ptrCast(*?windows.CRITICAL_SECTION, ctx); + if (mutex.* == null) { + var lock: windows.CRITICAL_SECTION = undefined; + windows.InitializeCriticalSection(&lock); + mutex.* = lock; + } + return windows.TRUE; + } + return windows.FALSE; } pub fn deinit(self: *Mutex) void { - if (self.lock != null) { - windows.DeleteCriticalSection(self.lock); - self.lock = null; + if (self.lock) |*lock| { + windows.DeleteCriticalSection(lock); } } pub fn acquire(self: *Mutex) Held { - windows.EnterCriticalSection(self.lock); + if (self.lock) |*lock| { + windows.EnterCriticalSection(lock); + } else { + if (windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, null, @ptrCast(?*windows.PVOID, self)) == windows.TRUE) { + windows.EnterCriticalSection(&self.lock.?); + } else { + @panic("unable to initialize Mutex"); + } + } + return Held { .mutex = self }; } }, @@ -116,7 +142,7 @@ pub const Mutex = switch(builtin.os) { }, }; -const Context = struct { +const TestContext = struct { mutex: *Mutex, data: i128, @@ -136,7 +162,7 @@ test "std.Mutex" { var mutex = Mutex.init(); defer mutex.deinit(); - var context = Context{ + var context = TestContext{ .mutex = &mutex, .data = 0, }; @@ -149,12 +175,12 @@ test "std.Mutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * Context.incr_count); + std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); } -fn worker(ctx: *Context) void { +fn worker(ctx: *TestContext) void { var i: usize = 0; - while (i != Context.incr_count) : (i += 1) { + while (i != TestContext.incr_count) : (i += 1) { const held = ctx.mutex.acquire(); defer held.release(); diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 3d6ee67113..3f19905835 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -49,6 +49,7 @@ pub const UNICODE = false; pub const WCHAR = u16; pub const WORD = u16; pub const LARGE_INTEGER = i64; +pub const LONG = c_long; pub const TRUE = 1; pub const FALSE = 0; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index e34092ad51..07d6cd80a2 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -221,10 +221,10 @@ pub const FOREGROUND_GREEN = 2; pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; -pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: ?*RTL_CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; pub const LIST_ENTRY = extern struct { Flink: *LIST_ENTRY, @@ -245,9 +245,21 @@ pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { pub const RTL_CRITICAL_SECTION = extern struct { DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, - LockCount: i32, - RecursionCount: i32, + LockCount: LONG, + RecursionCount: LONG, OwningThread: HANDLE, LockSemaphore: HANDLE, SpinCount: ULONG_PTR, }; + +pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; + +pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *PINIT_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?*LPVOID) BOOL; + +pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *PINIT_ONCE, Parameter: ?PVOID, Context: ?*PVOID) BOOL; + +pub const RTL_RUN_ONCE = extern struct { + Ptr: PVOID, +}; + +pub const PINIT_ONCE = RTL_RUN_ONCE; From 93851270526e71407b4225a23daa66214a4010f9 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 27 Nov 2018 01:39:37 -0600 Subject: [PATCH 103/218] changed pointer types --- std/mutex.zig | 7 ++++--- std/os/windows/kernel32.zig | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 45336f353e..3469b9a118 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -82,9 +82,9 @@ pub const Mutex = switch(builtin.os) { }; } - extern fn initCriticalSection(InitOnce: *windows.PINIT_ONCE, Parameter: ?windows.PVOID, Context: ?*windows.PVOID) windows.BOOL { + extern fn initCriticalSection(InitOnce: *windows.PINIT_ONCE, Parameter: ?windows.PVOID, Context: ?windows.PVOID) windows.BOOL { if (Context) |ctx| { - var mutex = @ptrCast(*?windows.CRITICAL_SECTION, ctx); + var mutex = @ptrCast(*?windows.CRITICAL_SECTION, @alignCast(8, ctx)); if (mutex.* == null) { var lock: windows.CRITICAL_SECTION = undefined; windows.InitializeCriticalSection(&lock); @@ -105,7 +105,8 @@ pub const Mutex = switch(builtin.os) { if (self.lock) |*lock| { windows.EnterCriticalSection(lock); } else { - if (windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, null, @ptrCast(?*windows.PVOID, self)) == windows.TRUE) { + var mutex = @ptrCast(?windows.PVOID, self); + if (windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, null, mutex) == windows.TRUE) { windows.EnterCriticalSection(&self.lock.?); } else { @panic("unable to initialize Mutex"); diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 07d6cd80a2..56e2163fb6 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -254,9 +254,9 @@ pub const RTL_CRITICAL_SECTION = extern struct { pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; -pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *PINIT_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?*LPVOID) BOOL; +pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *PINIT_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?LPVOID) BOOL; -pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *PINIT_ONCE, Parameter: ?PVOID, Context: ?*PVOID) BOOL; +pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *PINIT_ONCE, Parameter: ?PVOID, Context: ?PVOID) BOOL; pub const RTL_RUN_ONCE = extern struct { Ptr: PVOID, From 35d93d22db6f1cdf20011b0db84586107513b462 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 27 Nov 2018 16:20:09 +0000 Subject: [PATCH 104/218] removed nullables --- std/mutex.zig | 55 ++++++++++++++++--------------------- std/os/windows/kernel32.zig | 12 ++++---- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 3469b9a118..30b68511ea 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -62,57 +62,50 @@ pub const Mutex = switch(builtin.os) { }, builtin.Os.windows => struct { - lock: ?windows.CRITICAL_SECTION, - init_once: windows.PINIT_ONCE, + lock: windows.CRITICAL_SECTION, + init_once: windows.RTL_RUN_ONCE, pub const Held = struct { mutex: *Mutex, pub fn release(self: Held) void { - if (self.mutex.lock) |*lock| { - windows.LeaveCriticalSection(lock); - } + windows.LeaveCriticalSection(&self.mutex.lock); } }; pub fn init() Mutex { - return Mutex { - .lock = null, + return Mutex { + .lock = undefined, .init_once = undefined, }; } - extern fn initCriticalSection(InitOnce: *windows.PINIT_ONCE, Parameter: ?windows.PVOID, Context: ?windows.PVOID) windows.BOOL { - if (Context) |ctx| { - var mutex = @ptrCast(*?windows.CRITICAL_SECTION, @alignCast(8, ctx)); - if (mutex.* == null) { - var lock: windows.CRITICAL_SECTION = undefined; - windows.InitializeCriticalSection(&lock); - mutex.* = lock; - } - return windows.TRUE; - } - return windows.FALSE; + extern fn initCriticalSection( + InitOnce: *windows.RTL_RUN_ONCE, + Parameter: ?windows.PVOID, + Context: ?windows.PVOID + ) windows.BOOL { + var lock = @ptrCast( + *windows.CRITICAL_SECTION, + @alignCast(@alignOf(*windows.CRITICAL_SECTION), ctx.?) + ); + windows.InitializeCriticalSection(lock); + return windows.TRUE; } pub fn deinit(self: *Mutex) void { - if (self.lock) |*lock| { - windows.DeleteCriticalSection(lock); - } + windows.DeleteCriticalSection(&self.lock); } pub fn acquire(self: *Mutex) Held { - if (self.lock) |*lock| { - windows.EnterCriticalSection(lock); - } else { - var mutex = @ptrCast(?windows.PVOID, self); - if (windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, null, mutex) == windows.TRUE) { - windows.EnterCriticalSection(&self.lock.?); - } else { - @panic("unable to initialize Mutex"); - } + if (windows.InitOnceExecuteOnce( + &self.init_once, + initCriticalSection, + null, @ptrCast(?windows.PVOID, self) + ) == windows.FALSE) { + unreachable; } - + windows.EnterCriticalSection(&self.lock); return Held { .mutex = self }; } }, diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 56e2163fb6..a0b23acf5d 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -222,9 +222,9 @@ pub const FOREGROUND_RED = 4; pub const FOREGROUND_INTENSITY = 8; pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; -pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; +pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; pub const LIST_ENTRY = extern struct { Flink: *LIST_ENTRY, @@ -254,12 +254,10 @@ pub const RTL_CRITICAL_SECTION = extern struct { pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; -pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *PINIT_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?LPVOID) BOOL; +pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *RTL_RUN_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?LPVOID) BOOL; -pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *PINIT_ONCE, Parameter: ?PVOID, Context: ?PVOID) BOOL; +pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *RTL_RUN_ONCE, Parameter: ?PVOID, Context: ?PVOID) BOOL; pub const RTL_RUN_ONCE = extern struct { Ptr: PVOID, }; - -pub const PINIT_ONCE = RTL_RUN_ONCE; From 51fff9fa8212f514f76ef69c214e570d4ef98655 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 27 Nov 2018 17:43:59 +0000 Subject: [PATCH 105/218] fixed initializer and typos --- std/mutex.zig | 4 ++-- std/os/windows/kernel32.zig | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/std/mutex.zig b/std/mutex.zig index 30b68511ea..2885a99ed7 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -76,7 +76,7 @@ pub const Mutex = switch(builtin.os) { pub fn init() Mutex { return Mutex { .lock = undefined, - .init_once = undefined, + .init_once = windows.INIT_ONCE_STATIC_INIT, }; } @@ -87,7 +87,7 @@ pub const Mutex = switch(builtin.os) { ) windows.BOOL { var lock = @ptrCast( *windows.CRITICAL_SECTION, - @alignCast(@alignOf(*windows.CRITICAL_SECTION), ctx.?) + @alignCast(@alignOf(*windows.CRITICAL_SECTION), Context.?) ); windows.InitializeCriticalSection(lock); return windows.TRUE; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index a0b23acf5d..8fd351c125 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -261,3 +261,7 @@ pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *RTL_RUN_ONCE, Parameter: ?PVOID, pub const RTL_RUN_ONCE = extern struct { Ptr: PVOID, }; + +pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE { + .Ptr = null, +}; \ No newline at end of file From 3ff9ab332cf909da12361bf6ea495b2025ca8833 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 27 Nov 2018 17:54:09 +0000 Subject: [PATCH 106/218] fixed type signature --- std/os/windows/kernel32.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 8fd351c125..7a6126133a 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -259,7 +259,7 @@ pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *RTL_RUN_ONCE, pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *RTL_RUN_ONCE, Parameter: ?PVOID, Context: ?PVOID) BOOL; pub const RTL_RUN_ONCE = extern struct { - Ptr: PVOID, + Ptr: ?PVOID, }; pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE { From 404c87b06afbeebfea6c839665918c7bd1328d74 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Jan 2019 18:11:17 -0500 Subject: [PATCH 107/218] fix incorrect parameter names for std.math.atan2 --- std/math/atan2.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/math/atan2.zig b/std/math/atan2.zig index b3e45ba045..a7757132d7 100644 --- a/std/math/atan2.zig +++ b/std/math/atan2.zig @@ -22,10 +22,10 @@ const std = @import("../index.zig"); const math = std.math; const assert = std.debug.assert; -pub fn atan2(comptime T: type, x: T, y: T) T { +pub fn atan2(comptime T: type, y: T, x: T) T { return switch (T) { - f32 => atan2_32(x, y), - f64 => atan2_64(x, y), + f32 => atan2_32(y, x), + f64 => atan2_64(y, x), else => @compileError("atan2 not implemented for " ++ @typeName(T)), }; } From 5ab8db7b3ed902159f45a1c76e9c096439f6f0d7 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sat, 12 Jan 2019 20:13:06 +0100 Subject: [PATCH 108/218] removed unnecessary cast --- std/debug/index.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 3050d15c59..7948f5a388 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -247,8 +247,7 @@ pub fn writeCurrentStackTraceWindows( start_addr: ?usize, ) !void { var addr_buf: [1024]usize = undefined; - const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast - const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null); + 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| { From a60ecdc6815555c59cd671e7846b1058be3f07fd Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Thu, 17 Jan 2019 01:06:26 +0100 Subject: [PATCH 109/218] Hopefully fixed #1503 (at least improved) line accuracy of stack traces on windows. --- std/debug/index.zig | 68 ++++++++++++++++++++++++++++++--------------- std/pdb.zig | 12 ++++++++ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 7948f5a388..445f943594 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -337,50 +337,74 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres switch (subsect_hdr.Kind) { pdb.DebugSubsectionKind.Lines => { - var line_index: usize = sect_offset; + 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 block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]); - line_index += @sizeOf(pdb.LineBlockFragmentHeader); - - const has_column = line_hdr.Flags.LF_HaveColumns; - const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; - if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) { - var line_i: usize = 0; + + // 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; - 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 flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags); - const vaddr_start = frag_vaddr_start + line_num_entry.Offset; - const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End; - if (relative_address >= vaddr_start and relative_address < vaddr_end) { + + 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 = flags.Start; + + const line_entry_idx = line_i - 1; + const column = if (has_column) blk: { - line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines; - line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i; - const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]); + 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 = line, + .line = flags.Start, .column = column, }; } } - break :subsections null; + } + + // Checking that we are not reading garbage after the (possibly) multiple block fragments. + if (line_index != subsection_end_index) { + return error.InvalidDebugInfo; } }, else => {}, diff --git a/std/pdb.zig b/std/pdb.zig index 0cfc6a6cda..b6e48ad2f7 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -9,6 +9,10 @@ const coff = std.coff; 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, @@ -345,6 +349,10 @@ pub const RecordPrefix = packed struct { RecordKind: SymbolKind, }; +/// The following variable length array appears immediately after the header. +/// The structure definition follows. +/// LineBlockFragmentHeader Blocks[] +/// Each `LineBlockFragmentHeader` as specified below. pub const LineFragmentHeader = packed struct { /// Code offset of line contribution. RelocOffset: u32, @@ -386,7 +394,11 @@ pub const LineNumberEntry = packed struct { /// TODO runtime crash when I make the actual type of Flags this 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, IsStatement: bool, }; From 0d1ce1fb5fb4bcfff0dc24b567220af6ec6b93ab Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Sun, 20 Jan 2019 16:57:13 +0900 Subject: [PATCH 110/218] src/analyze.cpp: return type entry for `ZigTypeIdPointer` if it points to `ZigTypeIdOpaque` ref: ziglang/zig#1883 --- src/analyze.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 00eb38de9e..15370983fc 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5751,6 +5751,13 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v } void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { + assert(type_entry->id == ZigTypeIdPointer); + + if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { + buf_append_buf(buf, &type_entry->name); + return; + } + switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); From 1357bc7430e48137b249c6930b4f03c48efa0f33 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 20 Jan 2019 14:09:17 -0500 Subject: [PATCH 111/218] add test case for previous commit --- test/compile_errors.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 880a96a322..d9603ba4ff 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "compile log a pointer to an opaque value", + \\export fn entry() void { + \\ @compileLog(@ptrCast(*const c_void, &entry)); + \\} + , + ".tmp_source.zig:2:5: error: found compile log statement", + ); + cases.add( "duplicate boolean switch value", \\comptime { From 3bec3b9f9ba49bbc2e7244737c50bdbaa12a6b14 Mon Sep 17 00:00:00 2001 From: tharvik Date: Sat, 19 Jan 2019 16:47:33 +0100 Subject: [PATCH 112/218] llvm-config sanity check --- cmake/Findllvm.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmake/Findllvm.cmake b/cmake/Findllvm.cmake index b847813682..70d50f9843 100644 --- a/cmake/Findllvm.cmake +++ b/cmake/Findllvm.cmake @@ -15,6 +15,15 @@ find_program(LLVM_CONFIG_EXE "c:/msys64/mingw64/bin" "C:/Libraries/llvm-7.0.0/bin") +execute_process( + COMMAND ${LLVM_CONFIG_EXE} --version + OUTPUT_VARIABLE LLVM_CONFIG_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + +if(LLVM_CONFIG_VERSION VERSION_LESS 7) + message(FATAL_ERROR "expected LLVM version >=7 but found ${LLVM_CONFIG_VERSION}") +endif() + if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC) execute_process( COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static From 5bf9ffdc5be02e67b57fe9398ad9d13147bfb0c8 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Sat, 26 Jan 2019 05:10:40 +0900 Subject: [PATCH 113/218] Hint at use of and/or when &&/|| is improperly used (#1886) --- doc/langref.html.in | 2 +- src/ir.cpp | 227 +++++++++++++++++----------------------- src/parser.cpp | 35 +++++-- src/tokenizer.cpp | 12 +++ src/tokenizer.hpp | 1 + test/compile_errors.zig | 145 +++++++++++++++---------- 6 files changed, 226 insertions(+), 196 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 6e03d3ec6d..1fb751cef4 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6024,7 +6024,7 @@ fn add(a: i32, b: i32) i32 { This is typically used for type safety when interacting with C code that does not expose struct details. Example:

- {#code_begin|test_err|expected type '*Derp', found '*Wat'#} + {#code_begin|test_err|expected '*Derp' type, found '*Wat'#} const Derp = @OpaqueType(); const Wat = @OpaqueType(); diff --git a/src/ir.cpp b/src/ir.cpp index c651f30dd5..df2c8cc9be 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9771,13 +9771,19 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node return ir_exec_const_result(codegen, analyzed_executable); } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { +static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTypeId wanted_type) { if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; + const char *expected_type_str = type_id_name(ZigTypeIdMetaType); + + if (wanted_type != ZigTypeIdInvalid) { + expected_type_str = type_id_name(wanted_type); + } + if (type_value->value.type->id != ZigTypeIdMetaType) { - ir_add_error(ira, type_value, - buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); + ir_add_error( ira, type_value, + buf_sprintf("expected %s type, found '%s'", expected_type_str, buf_ptr(&type_value->value.type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -9786,7 +9792,16 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { return ira->codegen->builtin_types.entry_invalid; assert(const_val->data.x_type != nullptr); - return const_val->data.x_type; + + ZigType *out_type = const_val->data.x_type; + + if (wanted_type != ZigTypeIdInvalid && out_type->id != wanted_type) { + ir_add_error(ira, type_value, + buf_sprintf( "expected %s type, found '%s'", expected_type_str, buf_ptr(&out_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + return out_type; } static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { @@ -10986,7 +11001,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("expected type '%s', found '%s'", + buf_sprintf("expected '%s' type, found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name))); report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg); @@ -12214,7 +12229,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t op2_array_end; if (op2_type->id == ZigTypeIdArray) { if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12228,7 +12243,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.data.base_array.is_cstr) { if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12239,7 +12254,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12253,7 +12268,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); + buf_sprintf("expected array or C string literal type, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } @@ -12388,26 +12403,22 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { - ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child); - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_instruction; - - if (op1_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->op1, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&op1_type->name))); + ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child, ZigTypeIdErrorSet); + if (type_is_invalid(op1_type)) { + if (ira->codegen->errors.length != 0) { + add_error_note( ira->codegen + , ira->codegen->errors.last() + , instruction->base.source_node + , buf_sprintf("did you mean to use `or`?") + ); + } return ira->codegen->invalid_instruction; } - ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child); + ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child, ZigTypeIdErrorSet); if (type_is_invalid(op2_type)) return ira->codegen->invalid_instruction; - if (op2_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->op2, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&op2_type->name))); - return ira->codegen->invalid_instruction; - } - if (type_is_global_error_set(op1_type) || type_is_global_error_set(op2_type)) { @@ -12495,7 +12506,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct IrInstruction *var_type = nullptr; if (decl_var_instruction->var_type != nullptr) { var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type); + ZigType *proposed_type = ir_resolve_type(ira, var_type, ZigTypeIdInvalid); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { var->value->type = ira->codegen->builtin_types.entry_invalid; @@ -12824,21 +12835,14 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, { Error err; - ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); + ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child, ZigTypeIdErrorSet); if (type_is_invalid(err_set_type)) return ira->codegen->invalid_instruction; - ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child, ZigTypeIdInvalid); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; - if (err_set_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->err_set->child, - buf_sprintf("expected error set type, found type '%s'", - buf_ptr(&err_set_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); @@ -12900,7 +12904,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type; if (alloc_fn_type->id != ZigTypeIdFn) { ir_add_error(ira, &call_instruction->base, - buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name))); + buf_sprintf("expected allocation function type, found '%s'", buf_ptr(&alloc_fn_type->name))); return ira->codegen->invalid_instruction; } @@ -13692,7 +13696,7 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC if (is_comptime || instr_is_comptime(fn_ref)) { if (fn_ref->value.type->id == ZigTypeIdMetaType) { - ZigType *dest_type = ir_resolve_type(ira, fn_ref); + ZigType *dest_type = ir_resolve_type(ira, fn_ref, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -13817,7 +13821,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { Error err; IrInstruction *value = un_op_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, value); + ZigType *type_entry = ir_resolve_type(ira, value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; if ((err = ensure_complete_type(ira->codegen, type_entry))) @@ -15300,16 +15304,10 @@ static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, IrInstructionPtrTypeChild *ptr_type_child_instruction) { IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdPointer); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - if (type_entry->id != ZigTypeIdPointer) { - ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, - buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); } @@ -15462,7 +15460,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); + ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -15545,7 +15543,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs AsmOutput *asm_output = asm_expr->output_list.at(i); if (asm_output->return_type) { output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i]); + return_type = ir_resolve_type(ira, output_types[i], ZigTypeIdInvalid); if (type_is_invalid(return_type)) return ira->codegen->invalid_instruction; } @@ -15560,7 +15558,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs (input_value->value.type->id == ZigTypeIdComptimeInt || input_value->value.type->id == ZigTypeIdComptimeFloat)) { ir_add_error_node(ira, input_value->source_node, - buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value.type->name))); + buf_sprintf("expected sized integer or sized float type, found %s", buf_ptr(&input_value->value.type->name))); return ira->codegen->invalid_instruction; } @@ -15586,7 +15584,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; IrInstruction *child_type_value = array_type_instruction->child_type->child; - ZigType *child_type = ir_resolve_type(ira, child_type_value); + ZigType *child_type = ir_resolve_type(ira, child_type_value, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; switch (child_type->id) { @@ -15635,7 +15633,7 @@ static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInst if (instruction->payload_type == nullptr) { promise_type = ira->codegen->builtin_types.entry_promise; } else { - ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child, ZigTypeIdInvalid); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; @@ -15650,7 +15648,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, { Error err; IrInstruction *type_value = size_of_instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if ((err = ensure_complete_type(ira->codegen, type_entry))) return ira->codegen->invalid_instruction; @@ -16485,7 +16483,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, size_t elem_count = instruction->item_count; if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16601,7 +16599,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16719,7 +16717,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value); + ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16732,12 +16730,6 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (type_is_invalid(field_ptr->value.type)) return ira->codegen->invalid_instruction; - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -16751,7 +16743,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (field_ptr->value.type->id != ZigTypeIdPointer) { ir_add_error(ira, field_ptr, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value.type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&field_ptr->value.type->name))); return ira->codegen->invalid_instruction; } @@ -16810,9 +16802,9 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { - ZigType *container_type = ir_resolve_type(ira, type_value); + ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); if (type_is_invalid(container_type)) return nullptr; @@ -16824,12 +16816,6 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, if (!field_name) return nullptr; - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return nullptr; - } - TypeStructField *field = find_struct_type_field(container_type, field_name); if (field == nullptr) { ir_add_error(ira, field_name_value, @@ -17807,7 +17793,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17835,7 +17821,7 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstructionTypeId *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17870,7 +17856,7 @@ static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ir static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -18147,7 +18133,7 @@ static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstruction static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18200,7 +18186,7 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstructionIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18233,7 +18219,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18273,16 +18259,10 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdErrorSet); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->dest_type, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *target = instruction->target->child; if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; @@ -18311,7 +18291,7 @@ static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_ali static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; - ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child); + ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_child_type)) return ira->codegen->invalid_instruction; @@ -18408,7 +18388,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct if (!is_slice(target->value.type)) { ir_add_error(ira, instruction->target, - buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected slice type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -18427,7 +18407,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18445,7 +18425,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18501,7 +18481,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr return ira->codegen->invalid_instruction; if (target->value.type->id != ZigTypeIdBool) { - ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'", + ir_add_error(ira, instruction->target, buf_sprintf("expected bool type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -19082,7 +19062,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst IrInstruction *container = instruction->container->child; if (type_is_invalid(container->value.type)) return ira->codegen->invalid_instruction; - ZigType *container_type = ir_resolve_type(ira, container); + ZigType *container_type = ir_resolve_type(ira, container, ZigTypeIdInvalid); if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -19116,7 +19096,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19159,7 +19139,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19252,7 +19232,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; @@ -19302,16 +19282,10 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *dest_type = ir_resolve_type(ira, type_value); + ZigType *dest_type = ir_resolve_type(ira, type_value, ZigTypeIdInt); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdInt) { - ir_add_error(ira, type_value, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -19581,7 +19555,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *param_type = ir_resolve_type(ira, param_type_value); + ZigType *param_type = ir_resolve_type(ira, param_type_value, ZigTypeIdInvalid); switch (type_requires_comptime(ira->codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -19615,7 +19589,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct } IrInstruction *return_type_value = instruction->return_type->child; - fn_type_id.return_type = ir_resolve_type(ira, return_type_value); + fn_type_id.return_type = ir_resolve_type(ira, return_type_value, ZigTypeIdInvalid); if (type_is_invalid(fn_type_id.return_type)) return ira->codegen->invalid_instruction; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { @@ -19631,7 +19605,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child; - fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); + fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value, ZigTypeIdInvalid); if (type_is_invalid(fn_type_id.async_allocator_type)) return ira->codegen->invalid_instruction; } @@ -19939,7 +19913,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 result_type = get_slice_type(ira->codegen, result_ptr_type); } else { ir_add_error(ira, target, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); + buf_sprintf("expected pointer or slice type, found '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; } @@ -19985,13 +19959,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // validate src_type and dest_type. if (get_src_ptr_type(src_type) == nullptr) { - ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); + ir_add_error(ira, ptr, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20059,7 +20033,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20255,7 +20229,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20352,13 +20326,13 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; // We explicitly check for the size, so we can use get_src_ptr_type if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + ir_add_error(ira, dest_type_value, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20461,7 +20435,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru // We check size explicitly so we can use get_src_ptr_type here. if (get_src_ptr_type(target->value.type) == nullptr) { ir_add_error(ira, target, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20492,7 +20466,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { Error err; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); + ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -20591,7 +20565,7 @@ static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrI static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) { IrInstruction *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); + ZigType *fn_type = ir_resolve_type(ira, fn_type_inst, ZigTypeIdFn); if (type_is_invalid(fn_type)) return ira->codegen->invalid_instruction; @@ -20600,11 +20574,6 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) return ira->codegen->invalid_instruction; - if (fn_type->id != ZigTypeIdFn) { - ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_instruction; - } - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; if (arg_index >= fn_type_id->param_count) { ir_add_error(ira, arg_index_inst, @@ -20629,7 +20598,7 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { Error err; IrInstruction *target_inst = instruction->target->child; - ZigType *enum_type = ir_resolve_type(ira, target_inst); + ZigType *enum_type = ir_resolve_type(ira, target_inst, ZigTypeIdInvalid); if (type_is_invalid(enum_type)) return ira->codegen->invalid_instruction; @@ -20654,7 +20623,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } } else { - ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", + ir_add_error(ira, target_inst, buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&enum_type->name))); return ira->codegen->invalid_instruction; } @@ -20808,7 +20777,7 @@ static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInst if (coro_handle->value.type->id != ZigTypeIdPromise || coro_handle->value.type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", buf_ptr(&coro_handle->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20839,7 +20808,7 @@ static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, I } static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { - ZigType *operand_type = ir_resolve_type(ira, op); + ZigType *operand_type = ir_resolve_type(ira, op, ZigTypeIdInvalid); if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; @@ -20969,12 +20938,12 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { - ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child); + ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child, ZigTypeIdInvalid); if (type_is_invalid(promise_type)) return ira->codegen->invalid_instruction; if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", buf_ptr(&promise_type->name))); return ira->codegen->invalid_instruction; } @@ -20983,7 +20952,7 @@ static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, } static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) { - ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child); + ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child, ZigTypeIdInvalid); if (type_is_invalid(promise_result_type)) return ira->codegen->invalid_instruction; @@ -21046,7 +21015,7 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i } static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { - ZigType *float_type = ir_resolve_type(ira, instruction->type->child); + ZigType *float_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(float_type)) return ira->codegen->invalid_instruction; @@ -21113,7 +21082,7 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS } static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21169,7 +21138,7 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction } static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21240,7 +21209,7 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr if (target->value.type->id != ZigTypeIdEnum) { ir_add_error(ira, instruction->target, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected enum type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -21255,16 +21224,10 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdEnum); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdEnum) { - ir_add_error(ira, instruction->dest_type, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; diff --git a/src/parser.cpp b/src/parser.cpp index 077365995e..9425df2430 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -122,19 +122,37 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc); static AstNode *ast_parse_byte_align(ParseContext *pc); ATTRIBUTE_PRINTF(3, 4) -ATTRIBUTE_NORETURN -static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { +static ErrorMsg *ast_error(ParseContext *pc, Token *token, const char *format, ...) { va_list ap; va_start(ap, format); Buf *msg = buf_vprintf(format, ap); 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); + err->line_start = token->start_line; + err->column_start = token->start_column; + + return err; +} + +ATTRIBUTE_PRINTF(4, 5) +ATTRIBUTE_NORETURN +static void ast_error_exit(ParseContext *pc, Token *token, ErrorMsg *note, const char *format, ...) { + va_list ap; + va_start(ap, format); + Buf *msg = buf_vprintf(format, ap); + 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); err->line_start = token->start_line; err->column_start = token->start_column; + if (note) { + err->notes.append(note); + } + print_err_msg(err, pc->err_color); exit(EXIT_FAILURE); } @@ -164,7 +182,7 @@ static Buf ast_token_str(Buf *input, Token *token) { ATTRIBUTE_NORETURN static void ast_invalid_token_error(ParseContext *pc, Token *token) { Buf token_value = ast_token_str(pc->buf, token); - ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); + ast_error_exit(pc, token, NULL, "invalid token: '%s'", buf_ptr(&token_value)); } static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { @@ -214,8 +232,13 @@ static Token *eat_token_if(ParseContext *pc, TokenId id) { static Token *expect_token(ParseContext *pc, TokenId id) { Token *res = eat_token(pc); - if (res->id != id) - ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); + if (res->id != id) { + ErrorMsg *note = NULL; + if (res->id == TokenIdAmpersandAmpersand) { + note = ast_error(pc, res, "did you mean to use `and`?"); + } + ast_error_exit(pc, res, note, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); + } return res; } @@ -837,7 +860,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { if (param_decl->data.param_decl.is_var_args) res->data.fn_proto.is_var_args = true; if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error(pc, first, "Function prototype have varargs as a none last paramter."); + ast_error_exit(pc, first, NULL, "Function prototype have varargs as a none last paramter."); } return res; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 921ee4de09..464412d443 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -199,6 +199,7 @@ enum TokenizeState { TokenizeStateSawDash, TokenizeStateSawMinusPercent, TokenizeStateSawAmpersand, + TokenizeStateSawAmpersandAmpersand, TokenizeStateSawCaret, TokenizeStateSawBar, TokenizeStateSawBarBar, @@ -891,6 +892,10 @@ void tokenize(Buf *buf, Tokenization *out) { end_token(&t); t.state = TokenizeStateStart; break; + case '&': + set_token_id(&t, t.cur_tok, TokenIdAmpersandAmpersand); + t.state = TokenizeStateSawAmpersandAmpersand; + break; default: t.pos -= 1; end_token(&t); @@ -898,6 +903,11 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; + case TokenizeStateSawAmpersandAmpersand: + t.pos -= 1; + end_token(&t); + t.state = TokenizeStateStart; + continue; case TokenizeStateSawCaret: switch (c) { case '=': @@ -1468,6 +1478,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawPlus: case TokenizeStateSawDash: case TokenizeStateSawAmpersand: + case TokenizeStateSawAmpersandAmpersand: case TokenizeStateSawCaret: case TokenizeStateSawBar: case TokenizeStateSawEq: @@ -1515,6 +1526,7 @@ void tokenize(Buf *buf, Tokenization *out) { const char * token_name(TokenId id) { switch (id) { case TokenIdAmpersand: return "&"; + case TokenIdAmpersandAmpersand: return "&&"; case TokenIdArrow: return "->"; case TokenIdAtSign: return "@"; case TokenIdBang: return "!"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 1574e95571..2e872ce4de 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -14,6 +14,7 @@ enum TokenId { TokenIdAmpersand, + TokenIdAmpersandAmpersand, TokenIdArrow, TokenIdAtSign, TokenIdBang, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d9603ba4ff..d262405feb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,36 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "Use of && in place of `and`", + \\export fn entry() void { + \\ if (true && false) return; + \\} + , + ".tmp_source.zig:2:14: error: expected token ')', found '&&'", + ".tmp_source.zig:2:14: note: did you mean to use `and`?", + ); + + cases.add( + "Use of || in place of `or` (using comptime_int)", + \\export fn entry() void { + \\ if (1 || 0) return; + \\} + , + ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'comptime_int'", + ".tmp_source.zig:2:11: note: did you mean to use `or`?", + ); + + cases.add( + "Use of || in place of `or` (using booleans)", + \\export fn entry() void { + \\ if (true || false) return; + \\} + , + ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'bool'", + ".tmp_source.zig:2:14: note: did you mean to use `or`?", + ); + cases.add( "compile log a pointer to an opaque value", \\export fn entry() void { @@ -68,7 +98,7 @@ 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: error: expected 'fn(i32) void' type, found 'fn(bool) void", ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'", ); @@ -104,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".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_source.zig:11:20: error: expected 'u8' type, found 'u16'", ); cases.add( @@ -124,7 +154,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_source.zig:2:14: error: expected 'f32' type, found 'f64'", ); cases.add( @@ -172,7 +202,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_source.zig:5:26: error: expected '*c_void' type, found '**u32'", ); cases.add( @@ -222,7 +252,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_source.zig:3:27: error: expected '[]u8' type, found '*const [1]u8'", ); cases.add( @@ -267,8 +297,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const Errors = error{} || u16; \\} , - ".tmp_source.zig:2:20: error: expected error set type, found 'u8'", - ".tmp_source.zig:5:31: error: expected error set type, found 'u16'", + ".tmp_source.zig:2:20: error: expected ErrorSet type, found 'u8'", + ".tmp_source.zig:2:23: note: did you mean to use `or`?", + ".tmp_source.zig:5:31: error: expected ErrorSet type, found 'u16'", ); cases.add( @@ -763,7 +794,7 @@ 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: error: expected '*Foo' type, 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", @@ -833,7 +864,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var y = p.*; \\} , - ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'", + ".tmp_source.zig:4:23: error: expected '*?*i32' type, found '**i32'", ); cases.add( @@ -842,7 +873,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_source.zig:2:30: error: expected '[*]const bool' type, found 'bool'", ); cases.add( @@ -887,7 +918,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_source.zig:2:13: error: expected 'i32' type, found 'type'", ); cases.add( @@ -921,7 +952,7 @@ 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: error: expected '?NextError!i32' type, 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", @@ -991,7 +1022,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @panic(e); \\} , - ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'", + ".tmp_source.zig:3:12: error: expected '[]const u8' type, found 'error{Foo}'", ); cases.add( @@ -1019,7 +1050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.ShouldBeCompileError; \\} , - ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'", + ".tmp_source.zig:6:17: error: expected 'void' type, found 'error{ShouldBeCompileError}'", ); cases.add( @@ -1062,7 +1093,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_source.zig:8:7: error: expected 'fn(*const u8) void' type, found 'fn(u8) void'", ); cases.add( @@ -1144,7 +1175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ E.One => {}, \\ } \\} - , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'"); + , ".tmp_source.zig:9:10: error: expected 'usize' type, found 'E'"); cases.add( "range operator in switch used on error set", @@ -1190,7 +1221,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_source.zig:2:15: error: expected ErrorSet type, found 'i32'", ); cases.add( @@ -1240,7 +1271,7 @@ 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: error: expected 'SmallErrorSet!i32' type, 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", ); @@ -1255,7 +1286,7 @@ 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: error: expected 'SmallErrorSet' type, found 'anyerror'", ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set", ); @@ -1282,7 +1313,7 @@ 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:7:19: error: expected 'Set2' type, found 'Set1'", ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set", ); @@ -1822,7 +1853,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_source.zig:1:18: error: expected 'noreturn' type, found 'void'", ); cases.add( @@ -1830,7 +1861,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_source.zig:1:12: error: expected 'i32' type, found 'void'", ); cases.add( @@ -1936,7 +1967,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return a; \\} , - ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'", + ".tmp_source.zig:3:12: error: expected 'i32' type, found '[*]const u8'", ); cases.add( @@ -1945,7 +1976,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (0) {} \\} , - ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'", + ".tmp_source.zig:2:9: error: expected 'bool' type, found 'comptime_int'", ); cases.add( @@ -2040,8 +2071,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_source.zig:4:11: error: expected 'usize' type, found 'bool'", + ".tmp_source.zig:4:24: error: expected 'usize' type, found 'bool'", ); cases.add( @@ -2455,7 +2486,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_source.zig:3:30: error: expected '*const i32' type, found '*const comptime_int'", ); cases.add( @@ -2533,7 +2564,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_source.zig:1:27: error: expected 'fn() void' type, found 'fn() i32'", ); cases.add( @@ -2545,7 +2576,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_source.zig:1:36: error: expected 'fn(i32) i32' type, found 'extern fn(i32) i32'", ); cases.add( @@ -2649,7 +2680,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_source.zig:1:16: error: expected '*u8' type, found '(null)'", ); cases.add( @@ -3289,7 +3320,7 @@ 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:2:5: error: expected 'void' type, found 'anyerror'", ".tmp_source.zig:1:15: note: return type declared here", ); @@ -3468,7 +3499,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ derp.init(); \\} , - ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'", + ".tmp_source.zig:14:5: error: expected 'i32' type, found 'Foo'", ); cases.add( @@ -3498,7 +3529,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.init(); \\} , - ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'", + ".tmp_source.zig:23:5: error: expected '*Allocator' type, found '*List'", ); cases.add( @@ -3670,7 +3701,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_source.zig:8:26: error: expected '*const u3' type, found '*align(:3:1) const u3'", ); cases.add( @@ -3799,7 +3830,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_source.zig:4:19: error: expected '*[]const u8' type, found '*const []const u8'", ); cases.addCase(x: { @@ -3831,7 +3862,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ foo(global_array); \\} , - ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'", + ".tmp_source.zig:4:9: error: expected '[]i32' type, found '[10]i32'", ); cases.add( @@ -3840,7 +3871,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrCast(usize, a); \\} , - ".tmp_source.zig:2:21: error: expected pointer, found 'usize'", + ".tmp_source.zig:2:21: error: expected Pointer type, found 'usize'", ); cases.add( @@ -3887,7 +3918,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_source.zig:3:28: error: expected Struct type, found 'i32'", ); cases.add( @@ -3911,7 +3942,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:5:38: error: expected pointer, found 'i32'", + ".tmp_source.zig:5:38: error: expected Pointer type, found 'i32'", ); cases.add( @@ -3952,7 +3983,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @byteOffsetOf(Foo, "a",); \\} , - ".tmp_source.zig:3:26: error: expected struct type, found 'i32'", + ".tmp_source.zig:3:26: error: expected Struct type, found 'i32'", ); cases.add( @@ -4066,7 +4097,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_source.zig:2:15: error: expected 'bool' type, found '?i32'", ); cases.add( @@ -4076,7 +4107,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_source.zig:2:15: error: expected 'bool' type, found 'anyerror!i32'", ); cases.add( @@ -4337,7 +4368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrToInt(x); \\} , - ".tmp_source.zig:2:22: error: expected pointer, found 'i32'", + ".tmp_source.zig:2:22: error: expected Pointer type, found 'i32'", ); cases.add( @@ -4373,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x << y; \\} , - ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'", + ".tmp_source.zig:2:17: error: expected 'u3' type, found 'u8'", ); cases.add( @@ -4402,7 +4433,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.* += 1; \\} , - ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'", + ".tmp_source.zig:8:13: error: expected '*u32' type, found '*align(1) u32'", ); cases.add( @@ -4446,7 +4477,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_source.zig:2:22: error: expected pointer or slice type, found 'u32'", ); cases.add( @@ -4459,7 +4490,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_source.zig:2:35: error: expected 'fn() align(8) i32' type, found 'fn() align(4) i32'", ); cases.add( @@ -4471,7 +4502,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_source.zig:4:32: error: expected '*i32' type, found '*align(1) i32'", ); cases.add( @@ -4506,7 +4537,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_source.zig:5:9: error: expected '*Derp' type, found '*c_void'", ); cases.add( @@ -4552,7 +4583,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_source.zig:3:50: error: expected 'AtomicOrder' type, found 'u32'", ); cases.add( @@ -4562,7 +4593,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_source.zig:3:32: error: expected 'GlobalLinkage' type, found 'u32'", ); cases.add( @@ -4739,7 +4770,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @ArgType(i32, 3); \\} , - ".tmp_source.zig:2:18: error: expected function, found 'i32'", + ".tmp_source.zig:2:18: error: expected Fn type, found 'i32'", ); cases.add( @@ -4837,7 +4868,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_source.zig:2:9: error: expected '*const u8' type, found '[5]u8'", ); cases.add( @@ -4906,7 +4937,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_source.zig:9:22: error: expected 'u2' type, found 'Small'", ); cases.add( @@ -4923,7 +4954,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_source.zig:10:31: error: expected 'u2' type, found 'u3'", ); cases.add( @@ -5320,7 +5351,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_source.zig:2:35: error: expected sized integer or sized float type, found comptime_int", ); cases.add( @@ -5329,6 +5360,6 @@ 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_source.zig:2:35: error: expected sized integer or sized float type, found comptime_float", ); } From dd5450e7b9f3a6eeb6c02b6a76c82fa3aff37180 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sat, 26 Jan 2019 13:51:50 +0100 Subject: [PATCH 114/218] translate-c: get real child type of array type for incomplete initializers and/or multi-dimensional arrays. --- src/translate_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 02fa3b24be..1cf30278fc 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4079,7 +4079,7 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const init_node->data.container_init_expr.type = arr_type_node; init_node->data.container_init_expr.kind = ContainerInitKindArray; - QualType child_qt = qt.getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType(); + QualType child_qt = qt.getTypePtr()->getAsArrayTypeUnsafe()->getElementType(); for (size_t i = 0; i < init_count; i += 1) { APValue &elem_ap_val = ap_value->getArrayInitializedElt(i); From b2662e443dac700efcc5c14bfb5ccb89a60cdb60 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sat, 26 Jan 2019 15:38:17 +0100 Subject: [PATCH 115/218] translate-c: correct array concatenation for incomplete C array initializers. --- src/translate_c.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 1cf30278fc..54a97039d9 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4076,6 +4076,9 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const unsigned leftover_count = all_count - init_count; AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr); AstNode *arr_type_node = trans_qual_type(c, qt, source_loc); + if (leftover_count != 0) { // We can't use the size of the final array for a partial initializer. + bigint_init_unsigned(arr_type_node->data.array_type.size->data.int_literal.bigint, init_count); + } init_node->data.container_init_expr.type = arr_type_node; init_node->data.container_init_expr.kind = ContainerInitKindArray; @@ -4097,10 +4100,14 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const if (filler_node == nullptr) return nullptr; + AstNode* filler_arr_type = trans_create_node(c, NodeTypeArrayType); + *filler_arr_type = *arr_type_node; + filler_arr_type->data.array_type.size = trans_create_node_unsigned(c, 1); + AstNode *filler_arr_1 = trans_create_node(c, NodeTypeContainerInitExpr); - init_node->data.container_init_expr.type = arr_type_node; - init_node->data.container_init_expr.kind = ContainerInitKindArray; - init_node->data.container_init_expr.entries.append(filler_node); + filler_arr_1->data.container_init_expr.type = filler_arr_type; + filler_arr_1->data.container_init_expr.kind = ContainerInitKindArray; + filler_arr_1->data.container_init_expr.entries.append(filler_node); AstNode *rhs_node; if (leftover_count == 1) { From 584cb1fcfea5ff9f708719e345d621af24fa141f Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sat, 26 Jan 2019 15:53:19 +0100 Subject: [PATCH 116/218] translate-c: only detect ints as negative if they are signed. --- src/translate_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 54a97039d9..4cd8ed5a58 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -468,7 +468,7 @@ static const char *decl_name(const Decl *decl) { static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { AstNode *node = trans_create_node(c, NodeTypeIntLiteral); node->data.int_literal.bigint = allocate(1); - bool is_negative = aps_int.isNegative(); + bool is_negative = aps_int.isSigned() && aps_int.isNegative(); if (!is_negative) { bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), false); return node; From f0d35d78b602859583773326a5ed2b53dfd70161 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sat, 26 Jan 2019 16:47:11 +0100 Subject: [PATCH 117/218] translate-c: avoid array concatenation if the init node is empty, for clarity. --- src/translate_c.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 4cd8ed5a58..574742631f 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4117,6 +4117,10 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const rhs_node = trans_create_node_bin_op(c, filler_arr_1, BinOpTypeArrayMult, amt_node); } + if (init_count == 0) { + return rhs_node; + } + return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node); } case APValue::LValue: { From 9c328b42916d463465b134457c7f13b5c65da406 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 29 Jan 2019 22:28:33 -0500 Subject: [PATCH 118/218] simpler implementation of `&&` and `||` hints This accomplishes the same goal, but with less changes, so that I can backport copy elision stuff easier. --- doc/langref.html.in | 2 +- src/ir.cpp | 235 ++++++++++++++++++++++++---------------- src/parser.cpp | 35 +----- src/tokenizer.cpp | 15 +-- src/tokenizer.hpp | 1 - test/compile_errors.zig | 152 +++++++++++++------------- 6 files changed, 228 insertions(+), 212 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 1fb751cef4..6e03d3ec6d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6024,7 +6024,7 @@ fn add(a: i32, b: i32) i32 { This is typically used for type safety when interacting with C code that does not expose struct details. Example:

- {#code_begin|test_err|expected '*Derp' type, found '*Wat'#} + {#code_begin|test_err|expected type '*Derp', found '*Wat'#} const Derp = @OpaqueType(); const Wat = @OpaqueType(); diff --git a/src/ir.cpp b/src/ir.cpp index df2c8cc9be..b184252a2e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9771,19 +9771,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node return ir_exec_const_result(codegen, analyzed_executable); } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTypeId wanted_type) { +static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; - const char *expected_type_str = type_id_name(ZigTypeIdMetaType); - - if (wanted_type != ZigTypeIdInvalid) { - expected_type_str = type_id_name(wanted_type); - } - if (type_value->value.type->id != ZigTypeIdMetaType) { - ir_add_error( ira, type_value, - buf_sprintf("expected %s type, found '%s'", expected_type_str, buf_ptr(&type_value->value.type->name))); + ir_add_error(ira, type_value, + buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -9792,16 +9786,35 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTy return ira->codegen->builtin_types.entry_invalid; assert(const_val->data.x_type != nullptr); + return const_val->data.x_type; +} - ZigType *out_type = const_val->data.x_type; +static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, IrInstruction *op_source, IrInstruction *type_value) { + if (type_is_invalid(type_value->value.type)) + return ira->codegen->builtin_types.entry_invalid; - if (wanted_type != ZigTypeIdInvalid && out_type->id != wanted_type) { - ir_add_error(ira, type_value, - buf_sprintf( "expected %s type, found '%s'", expected_type_str, buf_ptr(&out_type->name))); + if (type_value->value.type->id != ZigTypeIdMetaType) { + ErrorMsg *msg = ir_add_error(ira, type_value, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value.type->name))); + add_error_note(ira->codegen, msg, op_source->source_node, + buf_sprintf("`||` merges error sets; `or` performs boolean OR")); return ira->codegen->builtin_types.entry_invalid; } - return out_type; + ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); + if (!const_val) + return ira->codegen->builtin_types.entry_invalid; + + assert(const_val->data.x_type != nullptr); + ZigType *result_type = const_val->data.x_type; + if (result_type->id != ZigTypeIdErrorSet) { + ErrorMsg *msg = ir_add_error(ira, type_value, + buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name))); + add_error_note(ira->codegen, msg, op_source->source_node, + buf_sprintf("`||` merges error sets; `or` performs boolean OR")); + return ira->codegen->builtin_types.entry_invalid; + } + return result_type; } static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { @@ -11001,7 +11014,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("expected '%s' type, found '%s'", + buf_sprintf("expected type '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name))); report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg); @@ -12229,7 +12242,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t op2_array_end; if (op2_type->id == ZigTypeIdArray) { if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12243,7 +12256,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.data.base_array.is_cstr) { if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12254,7 +12267,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12268,7 +12281,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal type, found '%s'", buf_ptr(&op2->value.type->name))); + buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } @@ -12403,19 +12416,11 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { - ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child, ZigTypeIdErrorSet); - if (type_is_invalid(op1_type)) { - if (ira->codegen->errors.length != 0) { - add_error_note( ira->codegen - , ira->codegen->errors.last() - , instruction->base.source_node - , buf_sprintf("did you mean to use `or`?") - ); - } + ZigType *op1_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op1->child); + if (type_is_invalid(op1_type)) return ira->codegen->invalid_instruction; - } - ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child, ZigTypeIdErrorSet); + ZigType *op2_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op2->child); if (type_is_invalid(op2_type)) return ira->codegen->invalid_instruction; @@ -12506,7 +12511,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct IrInstruction *var_type = nullptr; if (decl_var_instruction->var_type != nullptr) { var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type, ZigTypeIdInvalid); + ZigType *proposed_type = ir_resolve_type(ira, var_type); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { var->value->type = ira->codegen->builtin_types.entry_invalid; @@ -12835,14 +12840,21 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, { Error err; - ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child, ZigTypeIdErrorSet); + ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); if (type_is_invalid(err_set_type)) return ira->codegen->invalid_instruction; - ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child, ZigTypeIdInvalid); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; + if (err_set_type->id != ZigTypeIdErrorSet) { + ir_add_error(ira, instruction->err_set->child, + buf_sprintf("expected error set type, found type '%s'", + buf_ptr(&err_set_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); @@ -12904,7 +12916,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type; if (alloc_fn_type->id != ZigTypeIdFn) { ir_add_error(ira, &call_instruction->base, - buf_sprintf("expected allocation function type, found '%s'", buf_ptr(&alloc_fn_type->name))); + buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name))); return ira->codegen->invalid_instruction; } @@ -13696,7 +13708,7 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC if (is_comptime || instr_is_comptime(fn_ref)) { if (fn_ref->value.type->id == ZigTypeIdMetaType) { - ZigType *dest_type = ir_resolve_type(ira, fn_ref, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, fn_ref); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -13821,7 +13833,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { Error err; IrInstruction *value = un_op_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; if ((err = ensure_complete_type(ira->codegen, type_entry))) @@ -15304,10 +15316,16 @@ static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, IrInstructionPtrTypeChild *ptr_type_child_instruction) { IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdPointer); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; + if (type_entry->id != ZigTypeIdPointer) { + ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, + buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); + return ira->codegen->invalid_instruction; + } + return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); } @@ -15460,7 +15478,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -15543,7 +15561,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs AsmOutput *asm_output = asm_expr->output_list.at(i); if (asm_output->return_type) { output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i], ZigTypeIdInvalid); + return_type = ir_resolve_type(ira, output_types[i]); if (type_is_invalid(return_type)) return ira->codegen->invalid_instruction; } @@ -15558,7 +15576,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs (input_value->value.type->id == ZigTypeIdComptimeInt || input_value->value.type->id == ZigTypeIdComptimeFloat)) { ir_add_error_node(ira, input_value->source_node, - buf_sprintf("expected sized integer or sized float type, found %s", buf_ptr(&input_value->value.type->name))); + buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value.type->name))); return ira->codegen->invalid_instruction; } @@ -15584,7 +15602,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; IrInstruction *child_type_value = array_type_instruction->child_type->child; - ZigType *child_type = ir_resolve_type(ira, child_type_value, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, child_type_value); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; switch (child_type->id) { @@ -15633,7 +15651,7 @@ static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInst if (instruction->payload_type == nullptr) { promise_type = ira->codegen->builtin_types.entry_promise; } else { - ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child, ZigTypeIdInvalid); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; @@ -15648,7 +15666,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, { Error err; IrInstruction *type_value = size_of_instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if ((err = ensure_complete_type(ira->codegen, type_entry))) return ira->codegen->invalid_instruction; @@ -16483,7 +16501,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, size_t elem_count = instruction->item_count; if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16599,7 +16617,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16717,7 +16735,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); + ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16730,6 +16748,12 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (type_is_invalid(field_ptr->value.type)) return ira->codegen->invalid_instruction; + if (container_type->id != ZigTypeIdStruct) { + ir_add_error(ira, type_value, + buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -16743,7 +16767,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (field_ptr->value.type->id != ZigTypeIdPointer) { ir_add_error(ira, field_ptr, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&field_ptr->value.type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value.type->name))); return ira->codegen->invalid_instruction; } @@ -16802,9 +16826,9 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { - ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); + ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) return nullptr; @@ -16816,6 +16840,12 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, if (!field_name) return nullptr; + if (container_type->id != ZigTypeIdStruct) { + ir_add_error(ira, type_value, + buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); + return nullptr; + } + TypeStructField *field = find_struct_type_field(container_type, field_name); if (field == nullptr) { ir_add_error(ira, field_name_value, @@ -17793,7 +17823,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17821,7 +17851,7 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstructionTypeId *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17856,7 +17886,7 @@ static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ir static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -18133,7 +18163,7 @@ static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstruction static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18186,7 +18216,7 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstructionIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18219,7 +18249,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18259,10 +18289,16 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdErrorSet); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdErrorSet) { + ir_add_error(ira, instruction->dest_type, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + IrInstruction *target = instruction->target->child; if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; @@ -18291,7 +18327,7 @@ static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_ali static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; - ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child, ZigTypeIdInvalid); + ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child); if (type_is_invalid(dest_child_type)) return ira->codegen->invalid_instruction; @@ -18388,7 +18424,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct if (!is_slice(target->value.type)) { ir_add_error(ira, instruction->target, - buf_sprintf("expected slice type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -18407,7 +18443,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18425,7 +18461,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18481,7 +18517,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr return ira->codegen->invalid_instruction; if (target->value.type->id != ZigTypeIdBool) { - ir_add_error(ira, instruction->target, buf_sprintf("expected bool type, found '%s'", + ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -19062,7 +19098,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst IrInstruction *container = instruction->container->child; if (type_is_invalid(container->value.type)) return ira->codegen->invalid_instruction; - ZigType *container_type = ir_resolve_type(ira, container, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container); if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -19096,7 +19132,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19139,7 +19175,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19232,7 +19268,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; @@ -19282,10 +19318,16 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *dest_type = ir_resolve_type(ira, type_value, ZigTypeIdInt); + ZigType *dest_type = ir_resolve_type(ira, type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdInt) { + ir_add_error(ira, type_value, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -19555,7 +19597,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *param_type = ir_resolve_type(ira, param_type_value, ZigTypeIdInvalid); + ZigType *param_type = ir_resolve_type(ira, param_type_value); switch (type_requires_comptime(ira->codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -19589,7 +19631,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct } IrInstruction *return_type_value = instruction->return_type->child; - fn_type_id.return_type = ir_resolve_type(ira, return_type_value, ZigTypeIdInvalid); + fn_type_id.return_type = ir_resolve_type(ira, return_type_value); if (type_is_invalid(fn_type_id.return_type)) return ira->codegen->invalid_instruction; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { @@ -19605,7 +19647,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child; - fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value, ZigTypeIdInvalid); + fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); if (type_is_invalid(fn_type_id.async_allocator_type)) return ira->codegen->invalid_instruction; } @@ -19913,7 +19955,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 result_type = get_slice_type(ira->codegen, result_ptr_type); } else { ir_add_error(ira, target, - buf_sprintf("expected pointer or slice type, found '%s'", buf_ptr(&target_type->name))); + buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; } @@ -19959,13 +20001,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // validate src_type and dest_type. if (get_src_ptr_type(src_type) == nullptr) { - ir_add_error(ira, ptr, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&src_type->name))); + ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_src, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20033,7 +20075,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20229,7 +20271,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20326,13 +20368,13 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; // We explicitly check for the size, so we can use get_src_ptr_type if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); + ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20435,7 +20477,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru // We check size explicitly so we can use get_src_ptr_type here. if (get_src_ptr_type(target->value.type) == nullptr) { ir_add_error(ira, target, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20466,7 +20508,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { Error err; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -20565,7 +20607,7 @@ static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrI static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) { IrInstruction *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst, ZigTypeIdFn); + ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); if (type_is_invalid(fn_type)) return ira->codegen->invalid_instruction; @@ -20574,6 +20616,11 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) return ira->codegen->invalid_instruction; + if (fn_type->id != ZigTypeIdFn) { + ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); + return ira->codegen->invalid_instruction; + } + FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; if (arg_index >= fn_type_id->param_count) { ir_add_error(ira, arg_index_inst, @@ -20598,7 +20645,7 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { Error err; IrInstruction *target_inst = instruction->target->child; - ZigType *enum_type = ir_resolve_type(ira, target_inst, ZigTypeIdInvalid); + ZigType *enum_type = ir_resolve_type(ira, target_inst); if (type_is_invalid(enum_type)) return ira->codegen->invalid_instruction; @@ -20623,7 +20670,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } } else { - ir_add_error(ira, target_inst, buf_sprintf("expected enum or union type, found '%s'", + ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", buf_ptr(&enum_type->name))); return ira->codegen->invalid_instruction; } @@ -20777,7 +20824,7 @@ static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInst if (coro_handle->value.type->id != ZigTypeIdPromise || coro_handle->value.type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", buf_ptr(&coro_handle->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20808,7 +20855,7 @@ static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, I } static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { - ZigType *operand_type = ir_resolve_type(ira, op, ZigTypeIdInvalid); + ZigType *operand_type = ir_resolve_type(ira, op); if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; @@ -20938,12 +20985,12 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { - ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child, ZigTypeIdInvalid); + ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child); if (type_is_invalid(promise_type)) return ira->codegen->invalid_instruction; if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", buf_ptr(&promise_type->name))); return ira->codegen->invalid_instruction; } @@ -20952,7 +20999,7 @@ static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, } static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) { - ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child, ZigTypeIdInvalid); + ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child); if (type_is_invalid(promise_result_type)) return ira->codegen->invalid_instruction; @@ -21015,7 +21062,7 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i } static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { - ZigType *float_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *float_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(float_type)) return ira->codegen->invalid_instruction; @@ -21082,7 +21129,7 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS } static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21138,7 +21185,7 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction } static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21209,7 +21256,7 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr if (target->value.type->id != ZigTypeIdEnum) { ir_add_error(ira, instruction->target, - buf_sprintf("expected enum type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -21224,10 +21271,16 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdEnum); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdEnum) { + ir_add_error(ira, instruction->dest_type, + buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; diff --git a/src/parser.cpp b/src/parser.cpp index 9425df2430..077365995e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -122,37 +122,19 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc); static AstNode *ast_parse_byte_align(ParseContext *pc); ATTRIBUTE_PRINTF(3, 4) -static ErrorMsg *ast_error(ParseContext *pc, Token *token, const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *msg = buf_vprintf(format, ap); - 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); - err->line_start = token->start_line; - err->column_start = token->start_column; - - return err; -} - -ATTRIBUTE_PRINTF(4, 5) ATTRIBUTE_NORETURN -static void ast_error_exit(ParseContext *pc, Token *token, ErrorMsg *note, const char *format, ...) { +static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { va_list ap; va_start(ap, format); Buf *msg = buf_vprintf(format, ap); 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); err->line_start = token->start_line; err->column_start = token->start_column; - if (note) { - err->notes.append(note); - } - print_err_msg(err, pc->err_color); exit(EXIT_FAILURE); } @@ -182,7 +164,7 @@ static Buf ast_token_str(Buf *input, Token *token) { ATTRIBUTE_NORETURN static void ast_invalid_token_error(ParseContext *pc, Token *token) { Buf token_value = ast_token_str(pc->buf, token); - ast_error_exit(pc, token, NULL, "invalid token: '%s'", buf_ptr(&token_value)); + ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); } static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { @@ -232,13 +214,8 @@ static Token *eat_token_if(ParseContext *pc, TokenId id) { static Token *expect_token(ParseContext *pc, TokenId id) { Token *res = eat_token(pc); - if (res->id != id) { - ErrorMsg *note = NULL; - if (res->id == TokenIdAmpersandAmpersand) { - note = ast_error(pc, res, "did you mean to use `and`?"); - } - ast_error_exit(pc, res, note, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); - } + if (res->id != id) + ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); return res; } @@ -860,7 +837,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { if (param_decl->data.param_decl.is_var_args) res->data.fn_proto.is_var_args = true; if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error_exit(pc, first, NULL, "Function prototype have varargs as a none last paramter."); + ast_error(pc, first, "Function prototype have varargs as a none last paramter."); } return res; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 464412d443..6215541876 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -199,7 +199,6 @@ enum TokenizeState { TokenizeStateSawDash, TokenizeStateSawMinusPercent, TokenizeStateSawAmpersand, - TokenizeStateSawAmpersandAmpersand, TokenizeStateSawCaret, TokenizeStateSawBar, TokenizeStateSawBarBar, @@ -887,15 +886,14 @@ void tokenize(Buf *buf, Tokenization *out) { break; case TokenizeStateSawAmpersand: switch (c) { + case '&': + tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); + break; case '=': set_token_id(&t, t.cur_tok, TokenIdBitAndEq); end_token(&t); t.state = TokenizeStateStart; break; - case '&': - set_token_id(&t, t.cur_tok, TokenIdAmpersandAmpersand); - t.state = TokenizeStateSawAmpersandAmpersand; - break; default: t.pos -= 1; end_token(&t); @@ -903,11 +901,6 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; - case TokenizeStateSawAmpersandAmpersand: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; case TokenizeStateSawCaret: switch (c) { case '=': @@ -1478,7 +1471,6 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawPlus: case TokenizeStateSawDash: case TokenizeStateSawAmpersand: - case TokenizeStateSawAmpersandAmpersand: case TokenizeStateSawCaret: case TokenizeStateSawBar: case TokenizeStateSawEq: @@ -1526,7 +1518,6 @@ void tokenize(Buf *buf, Tokenization *out) { const char * token_name(TokenId id) { switch (id) { case TokenIdAmpersand: return "&"; - case TokenIdAmpersandAmpersand: return "&&"; case TokenIdArrow: return "->"; case TokenIdAtSign: return "@"; case TokenIdBang: return "!"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 2e872ce4de..1574e95571 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -14,7 +14,6 @@ enum TokenId { TokenIdAmpersand, - TokenIdAmpersandAmpersand, TokenIdArrow, TokenIdAtSign, TokenIdBang, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d262405feb..0754f223e8 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,33 +2,28 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( - "Use of && in place of `and`", - \\export fn entry() void { - \\ if (true && false) return; + "attempted `&&`", + \\export fn entry(a: bool, b: bool) i32 { + \\ if (a && b) { + \\ return 1234; + \\ } + \\ return 5678; \\} , - ".tmp_source.zig:2:14: error: expected token ')', found '&&'", - ".tmp_source.zig:2:14: note: did you mean to use `and`?", + ".tmp_source.zig:2:11: error: `&&` is invalid. Note that `and` is boolean AND.", ); cases.add( - "Use of || in place of `or` (using comptime_int)", - \\export fn entry() void { - \\ if (1 || 0) return; + "attempted `||` on boolean values", + \\export fn entry(a: bool, b: bool) i32 { + \\ if (a || b) { + \\ return 1234; + \\ } + \\ return 5678; \\} , - ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'comptime_int'", - ".tmp_source.zig:2:11: note: did you mean to use `or`?", - ); - - cases.add( - "Use of || in place of `or` (using booleans)", - \\export fn entry() void { - \\ if (true || false) return; - \\} - , - ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'bool'", - ".tmp_source.zig:2:14: note: did you mean to use `or`?", + ".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", ); cases.add( @@ -98,7 +93,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ do_the_thing(bar); \\} , - ".tmp_source.zig:4:18: error: expected 'fn(i32) void' type, found 'fn(bool) void", + ".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'", ); @@ -134,7 +129,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".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 'u8' type, found 'u16'", + ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'", ); cases.add( @@ -154,7 +149,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , - ".tmp_source.zig:2:14: error: expected 'f32' type, found 'f64'", + ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'", ); cases.add( @@ -202,7 +197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var ptr2: *c_void = &b; \\} , - ".tmp_source.zig:5:26: error: expected '*c_void' type, found '**u32'", + ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'", ); cases.add( @@ -252,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const sliceA: []u8 = &buffer; \\} , - ".tmp_source.zig:3:27: error: expected '[]u8' type, found '*const [1]u8'", + ".tmp_source.zig:3:27: error: expected type '[]u8', found '*const [1]u8'", ); cases.add( @@ -297,9 +292,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const Errors = error{} || u16; \\} , - ".tmp_source.zig:2:20: error: expected ErrorSet type, found 'u8'", - ".tmp_source.zig:2:23: note: did you mean to use `or`?", - ".tmp_source.zig:5:31: error: expected ErrorSet type, found '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", ); cases.add( @@ -794,7 +790,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\fn bar(x: *b.Foo) void {} , - ".tmp_source.zig:6:10: error: expected '*Foo' type, found '*Foo'", + ".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", @@ -864,7 +860,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var y = p.*; \\} , - ".tmp_source.zig:4:23: error: expected '*?*i32' type, found '**i32'", + ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'", ); cases.add( @@ -873,7 +869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const x: [*]const bool = true; \\} , - ".tmp_source.zig:2:30: error: expected '[*]const bool' type, found 'bool'", + ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'", ); cases.add( @@ -918,7 +914,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var rule_set = try Foo.init(); \\} , - ".tmp_source.zig:2:13: error: expected 'i32' type, found 'type'", + ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'", ); cases.add( @@ -952,7 +948,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return null; \\} , - ".tmp_source.zig:5:34: error: expected '?NextError!i32' type, found '?OtherError!i32'", + ".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", @@ -1022,7 +1018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @panic(e); \\} , - ".tmp_source.zig:3:12: error: expected '[]const u8' type, found 'error{Foo}'", + ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'", ); cases.add( @@ -1050,7 +1046,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.ShouldBeCompileError; \\} , - ".tmp_source.zig:6:17: error: expected 'void' type, found 'error{ShouldBeCompileError}'", + ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'", ); cases.add( @@ -1093,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a(c); \\} , - ".tmp_source.zig:8:7: error: expected 'fn(*const u8) void' type, found 'fn(u8) void'", + ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'", ); cases.add( @@ -1175,7 +1171,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ E.One => {}, \\ } \\} - , ".tmp_source.zig:9:10: error: expected 'usize' type, found 'E'"); + , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'"); cases.add( "range operator in switch used on error set", @@ -1221,7 +1217,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const z = i32!i32; \\} , - ".tmp_source.zig:2:15: error: expected ErrorSet type, found 'i32'", + ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'", ); cases.add( @@ -1271,7 +1267,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32' type, found 'anyerror!i32'", + ".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", ); @@ -1286,7 +1282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:31: error: expected 'SmallErrorSet' type, found 'anyerror'", + ".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", ); @@ -1313,7 +1309,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: Set2 = set1; \\} , - ".tmp_source.zig:7:19: error: expected 'Set2' type, found '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", ); @@ -1853,7 +1849,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() noreturn {return;} \\export fn entry() void { a(); } , - ".tmp_source.zig:1:18: error: expected 'noreturn' type, found 'void'", + ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'", ); cases.add( @@ -1861,7 +1857,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() i32 {} \\export fn entry() void { _ = a(); } , - ".tmp_source.zig:1:12: error: expected 'i32' type, found 'void'", + ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'", ); cases.add( @@ -1967,7 +1963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return a; \\} , - ".tmp_source.zig:3:12: error: expected 'i32' type, found '[*]const u8'", + ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'", ); cases.add( @@ -1976,7 +1972,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (0) {} \\} , - ".tmp_source.zig:2:9: error: expected 'bool' type, found 'comptime_int'", + ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'", ); cases.add( @@ -2071,8 +2067,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ array[bad] = array[bad]; \\} , - ".tmp_source.zig:4:11: error: expected 'usize' type, found 'bool'", - ".tmp_source.zig:4:24: error: expected 'usize' type, found 'bool'", + ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", + ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'", ); cases.add( @@ -2486,7 +2482,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 '*const i32' type, found '*const comptime_int'", + ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'", ); cases.add( @@ -2564,7 +2560,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 'fn() void' type, found 'fn() i32'", + ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'", ); cases.add( @@ -2576,7 +2572,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(fns)); } , - ".tmp_source.zig:1:36: error: expected 'fn(i32) i32' type, found 'extern fn(i32) i32'", + ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'", ); cases.add( @@ -2680,7 +2676,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - ".tmp_source.zig:1:16: error: expected '*u8' type, found '(null)'", + ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'", ); cases.add( @@ -3320,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn something() anyerror!void { } , - ".tmp_source.zig:2:5: error: expected 'void' type, found 'anyerror'", + ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'", ".tmp_source.zig:1:15: note: return type declared here", ); @@ -3499,7 +3495,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ derp.init(); \\} , - ".tmp_source.zig:14:5: error: expected 'i32' type, found 'Foo'", + ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'", ); cases.add( @@ -3529,7 +3525,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.init(); \\} , - ".tmp_source.zig:23:5: error: expected '*Allocator' type, found '*List'", + ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'", ); cases.add( @@ -3701,7 +3697,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:8:26: error: expected '*const u3' type, found '*align(:3:1) const u3'", + ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'", ); cases.add( @@ -3830,7 +3826,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:4:19: error: expected '*[]const u8' type, found '*const []const u8'", + ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'", ); cases.addCase(x: { @@ -3862,7 +3858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ foo(global_array); \\} , - ".tmp_source.zig:4:9: error: expected '[]i32' type, found '[10]i32'", + ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'", ); cases.add( @@ -3871,7 +3867,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrCast(usize, a); \\} , - ".tmp_source.zig:2:21: error: expected Pointer type, found 'usize'", + ".tmp_source.zig:2:21: error: expected pointer, found 'usize'", ); cases.add( @@ -3918,7 +3914,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_source.zig:3:28: error: expected struct type, found 'i32'", ); cases.add( @@ -3942,7 +3938,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:5:38: error: expected Pointer type, found 'i32'", + ".tmp_source.zig:5:38: error: expected pointer, found 'i32'", ); cases.add( @@ -3983,7 +3979,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @byteOffsetOf(Foo, "a",); \\} , - ".tmp_source.zig:3:26: error: expected Struct type, found 'i32'", + ".tmp_source.zig:3:26: error: expected struct type, found 'i32'", ); cases.add( @@ -4097,7 +4093,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() ?i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected 'bool' type, found '?i32'", + ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'", ); cases.add( @@ -4107,7 +4103,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() anyerror!i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected 'bool' type, found 'anyerror!i32'", + ".tmp_source.zig:2:15: error: expected type 'bool', found 'anyerror!i32'", ); cases.add( @@ -4368,7 +4364,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrToInt(x); \\} , - ".tmp_source.zig:2:22: error: expected Pointer type, found 'i32'", + ".tmp_source.zig:2:22: error: expected pointer, found 'i32'", ); cases.add( @@ -4404,7 +4400,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x << y; \\} , - ".tmp_source.zig:2:17: error: expected 'u3' type, found 'u8'", + ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'", ); cases.add( @@ -4433,7 +4429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.* += 1; \\} , - ".tmp_source.zig:8:13: error: expected '*u32' type, found '*align(1) u32'", + ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'", ); cases.add( @@ -4477,7 +4473,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @alignCast(4, u32(3)); \\} , - ".tmp_source.zig:2:22: error: expected pointer or slice type, found 'u32'", + ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'", ); cases.add( @@ -4490,7 +4486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn alignedSmall() align(4) i32 { return 1234; } , - ".tmp_source.zig:2:35: error: expected 'fn() align(8) i32' type, found 'fn() align(4) i32'", + ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'", ); cases.add( @@ -4502,7 +4498,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x == 5678; \\} , - ".tmp_source.zig:4:32: error: expected '*i32' type, found '*align(1) i32'", + ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'", ); cases.add( @@ -4537,7 +4533,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ bar(@ptrCast(*c_void, &x)); \\} , - ".tmp_source.zig:5:9: error: expected '*Derp' type, found '*c_void'", + ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'", ); cases.add( @@ -4583,7 +4579,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 'AtomicOrder' type, found 'u32'", + ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'", ); cases.add( @@ -4593,7 +4589,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @export("entry", entry, u32(1234)); \\} , - ".tmp_source.zig:3:32: error: expected 'GlobalLinkage' type, found 'u32'", + ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'", ); cases.add( @@ -4770,7 +4766,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @ArgType(i32, 3); \\} , - ".tmp_source.zig:2:18: error: expected Fn type, found 'i32'", + ".tmp_source.zig:2:18: error: expected function, found 'i32'", ); cases.add( @@ -4868,7 +4864,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\pub extern fn foo(format: *const u8, ...) void; , - ".tmp_source.zig:2:9: error: expected '*const u8' type, found '[5]u8'", + ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'", ); cases.add( @@ -4937,7 +4933,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: u2 = Small.Two; \\} , - ".tmp_source.zig:9:22: error: expected 'u2' type, found 'Small'", + ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'", ); cases.add( @@ -4954,7 +4950,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x = @intToEnum(Small, y); \\} , - ".tmp_source.zig:10:31: error: expected 'u2' type, found 'u3'", + ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'", ); cases.add( @@ -5351,7 +5347,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 type, found comptime_int", + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", ); cases.add( @@ -5360,6 +5356,6 @@ 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 type, found comptime_float", + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", ); } From 581edd643fb18a66c472f77e2f8cd3f4cea524a2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 29 Jan 2019 21:47:26 -0500 Subject: [PATCH 119/218] backport copy elision changes This commit contains everything from the copy-elision-2 branch that does not have to do with copy elision directly, but is generally useful for master branch. * All const values know their parents, when applicable, not just structs and unions. * Null pointers in const values are represented explicitly, rather than as a HardCodedAddr value of 0. * Rename "maybe" to "optional" in various code locations. * Separate DeclVarSrc and DeclVarGen * Separate PtrCastSrc and PtrCastGen * Separate CmpxchgSrc and CmpxchgGen * Represent optional error set as an integer, using the 0 value. In a const value, it uses nullptr. * Introduce type_has_one_possible_value and use it where applicable. * Fix debug builds not setting memory to 0xaa when storing undefined. * Separate the type of a variable from the const value of a variable. * Use copy_const_val where appropriate. * Rearrange structs to pack data more efficiently. * Move test/cases/* to test/behavior/* * Use `std.debug.assertOrPanic` in behavior tests instead of `std.debug.assert`. * Fix outdated slice syntax in docs. --- build.zig | 5 +- doc/langref.html.in | 13 +- src/all_types.hpp | 165 +- src/analyze.cpp | 297 +++- src/analyze.hpp | 9 +- src/ast_render.cpp | 8 +- src/codegen.cpp | 385 +++-- src/ir.cpp | 1483 +++++++++-------- src/ir.hpp | 2 +- src/ir_print.cpp | 83 +- src/parser.cpp | 8 +- std/event/fs.zig | 49 +- test/behavior.zig | 82 - test/cases/array.zig | 173 -- test/cases/asm.zig | 48 - test/cases/bitreverse.zig | 81 - test/cases/bswap.zig | 32 - test/cases/import.zig | 10 - test/cases/optional.zig | 30 - test/cases/popcount.zig | 24 - test/cases/reflection.zig | 95 -- test/cases/sizeof_and_typeof.zig | 69 - test/cases/type_info.zig | 264 --- test/compile_errors.zig | 4 +- test/stage1/behavior.zig | 80 + test/{cases => stage1/behavior}/align.zig | 72 +- test/{cases => stage1/behavior}/alignof.zig | 7 +- test/stage1/behavior/array.zig | 270 +++ test/stage1/behavior/asm.zig | 92 + test/{cases => stage1/behavior}/atomics.zig | 32 +- .../behavior}/bit_shifting.zig | 10 +- test/{cases => stage1/behavior}/bitcast.zig | 9 +- test/stage1/behavior/bitreverse.zig | 81 + test/{cases => stage1/behavior}/bool.zig | 20 +- test/stage1/behavior/bswap.zig | 32 + test/{cases => stage1/behavior}/bugs/1076.zig | 4 +- test/{cases => stage1/behavior}/bugs/1111.zig | 0 test/{cases => stage1/behavior}/bugs/1277.zig | 0 test/{cases => stage1/behavior}/bugs/1322.zig | 4 +- test/{cases => stage1/behavior}/bugs/1381.zig | 0 test/{cases => stage1/behavior}/bugs/1421.zig | 4 +- test/{cases => stage1/behavior}/bugs/1442.zig | 0 test/{cases => stage1/behavior}/bugs/1486.zig | 6 +- test/{cases => stage1/behavior}/bugs/394.zig | 4 +- test/{cases => stage1/behavior}/bugs/655.zig | 4 +- .../behavior}/bugs/655_other_file.zig | 0 test/{cases => stage1/behavior}/bugs/656.zig | 4 +- test/{cases => stage1/behavior}/bugs/726.zig | 6 +- test/{cases => stage1/behavior}/bugs/828.zig | 0 test/{cases => stage1/behavior}/bugs/920.zig | 2 +- .../behavior}/byval_arg_var.zig | 4 +- test/{cases => stage1/behavior}/cancel.zig | 14 +- test/{cases => stage1/behavior}/cast.zig | 155 +- .../behavior}/const_slice_child.zig | 10 +- .../behavior}/coroutine_await_struct.zig | 6 +- .../{cases => stage1/behavior}/coroutines.zig | 40 +- test/{cases => stage1/behavior}/defer.zig | 24 +- test/{cases => stage1/behavior}/enum.zig | 76 +- .../behavior}/enum_with_members.zig | 10 +- test/{cases => stage1/behavior}/error.zig | 125 +- test/{cases => stage1/behavior}/eval.zig | 236 +-- .../behavior}/field_parent_ptr.zig | 14 +- test/{cases => stage1/behavior}/fn.zig | 39 +- .../behavior}/fn_in_struct_in_comptime.zig | 4 +- test/{cases => stage1/behavior}/for.zig | 10 +- test/{cases => stage1/behavior}/generics.zig | 46 +- test/{cases => stage1/behavior}/if.zig | 4 +- test/stage1/behavior/import.zig | 10 + .../behavior}/import/a_namespace.zig | 0 .../behavior}/incomplete_struct_param_tld.zig | 4 +- test/{cases => stage1/behavior}/inttoptr.zig | 1 - .../behavior}/ir_block_deps.zig | 6 +- test/{cases => stage1/behavior}/math.zig | 256 +-- .../behavior}/merge_error_sets.zig | 0 test/{cases => stage1/behavior}/misc.zig | 350 ++-- .../namespace_depends_on_compile_var/a.zig | 0 .../namespace_depends_on_compile_var/b.zig | 0 .../index.zig | 6 +- .../behavior}/new_stack_call.zig | 10 +- test/{cases => stage1/behavior}/null.zig | 34 +- test/stage1/behavior/optional.zig | 81 + test/{cases => stage1/behavior}/pointers.zig | 24 +- test/stage1/behavior/popcount.zig | 25 + test/{cases => stage1/behavior}/ptrcast.zig | 0 .../behavior}/pub_enum/index.zig | 6 +- .../behavior}/pub_enum/other.zig | 0 ...ef_var_in_if_after_if_2nd_switch_prong.zig | 10 +- test/stage1/behavior/reflection.zig | 96 ++ test/stage1/behavior/sizeof_and_typeof.zig | 69 + test/{cases => stage1/behavior}/slice.zig | 16 +- test/{cases => stage1/behavior}/struct.zig | 186 +-- .../struct_contains_null_ptr_itself.zig | 4 +- .../struct_contains_slice_of_itself.zig | 26 +- test/{cases => stage1/behavior}/switch.zig | 66 +- .../behavior}/switch_prong_err_enum.zig | 6 +- .../behavior}/switch_prong_implicit_cast.zig | 4 +- test/{cases => stage1/behavior}/syntax.zig | 1 + test/{cases => stage1/behavior}/this.zig | 9 +- test/{cases => stage1/behavior}/truncate.zig | 4 +- test/{cases => stage1/behavior}/try.zig | 10 +- test/stage1/behavior/type_info.zig | 264 +++ test/{cases => stage1/behavior}/undefined.zig | 29 +- .../{cases => stage1/behavior}/underscore.zig | 2 +- test/{cases => stage1/behavior}/union.zig | 76 +- test/{cases => stage1/behavior}/var_args.zig | 34 +- test/{cases => stage1/behavior}/void.zig | 11 +- test/{cases => stage1/behavior}/while.zig | 45 +- test/{cases => stage1/behavior}/widening.zig | 9 +- 108 files changed, 3836 insertions(+), 2933 deletions(-) delete mode 100644 test/behavior.zig delete mode 100644 test/cases/array.zig delete mode 100644 test/cases/asm.zig delete mode 100644 test/cases/bitreverse.zig delete mode 100644 test/cases/bswap.zig delete mode 100644 test/cases/import.zig delete mode 100644 test/cases/optional.zig delete mode 100644 test/cases/popcount.zig delete mode 100644 test/cases/reflection.zig delete mode 100644 test/cases/sizeof_and_typeof.zig delete mode 100644 test/cases/type_info.zig create mode 100644 test/stage1/behavior.zig rename test/{cases => stage1/behavior}/align.zig (69%) rename test/{cases => stage1/behavior}/alignof.zig (61%) create mode 100644 test/stage1/behavior/array.zig create mode 100644 test/stage1/behavior/asm.zig rename test/{cases => stage1/behavior}/atomics.zig (65%) rename test/{cases => stage1/behavior}/bit_shifting.zig (90%) rename test/{cases => stage1/behavior}/bitcast.zig (78%) create mode 100644 test/stage1/behavior/bitreverse.zig rename test/{cases => stage1/behavior}/bool.zig (50%) create mode 100644 test/stage1/behavior/bswap.zig rename test/{cases => stage1/behavior}/bugs/1076.zig (75%) rename test/{cases => stage1/behavior}/bugs/1111.zig (100%) rename test/{cases => stage1/behavior}/bugs/1277.zig (100%) rename test/{cases => stage1/behavior}/bugs/1322.zig (66%) rename test/{cases => stage1/behavior}/bugs/1381.zig (100%) rename test/{cases => stage1/behavior}/bugs/1421.zig (70%) rename test/{cases => stage1/behavior}/bugs/1442.zig (100%) rename test/{cases => stage1/behavior}/bugs/1486.zig (51%) rename test/{cases => stage1/behavior}/bugs/394.zig (68%) rename test/{cases => stage1/behavior}/bugs/655.zig (67%) rename test/{cases => stage1/behavior}/bugs/655_other_file.zig (100%) rename test/{cases => stage1/behavior}/bugs/656.zig (84%) rename test/{cases => stage1/behavior}/bugs/726.zig (71%) rename test/{cases => stage1/behavior}/bugs/828.zig (100%) rename test/{cases => stage1/behavior}/bugs/920.zig (95%) rename test/{cases => stage1/behavior}/byval_arg_var.zig (70%) rename test/{cases => stage1/behavior}/cancel.zig (84%) rename test/{cases => stage1/behavior}/cast.zig (67%) rename test/{cases => stage1/behavior}/const_slice_child.zig (80%) rename test/{cases => stage1/behavior}/coroutine_await_struct.zig (86%) rename test/{cases => stage1/behavior}/coroutines.zig (86%) rename test/{cases => stage1/behavior}/defer.zig (72%) rename test/{cases => stage1/behavior}/enum.zig (84%) rename test/{cases => stage1/behavior}/enum_with_members.zig (63%) rename test/{cases => stage1/behavior}/error.zig (58%) rename test/{cases => stage1/behavior}/eval.zig (70%) rename test/{cases => stage1/behavior}/field_parent_ptr.zig (69%) rename test/{cases => stage1/behavior}/fn.zig (78%) rename test/{cases => stage1/behavior}/fn_in_struct_in_comptime.zig (72%) rename test/{cases => stage1/behavior}/for.zig (89%) rename test/{cases => stage1/behavior}/generics.zig (68%) rename test/{cases => stage1/behavior}/if.zig (85%) create mode 100644 test/stage1/behavior/import.zig rename test/{cases => stage1/behavior}/import/a_namespace.zig (100%) rename test/{cases => stage1/behavior}/incomplete_struct_param_tld.zig (78%) rename test/{cases => stage1/behavior}/inttoptr.zig (99%) rename test/{cases => stage1/behavior}/ir_block_deps.zig (64%) rename test/{cases => stage1/behavior}/math.zig (56%) rename test/{cases => stage1/behavior}/merge_error_sets.zig (100%) rename test/{cases => stage1/behavior}/misc.zig (61%) rename test/{cases => stage1/behavior}/namespace_depends_on_compile_var/a.zig (100%) rename test/{cases => stage1/behavior}/namespace_depends_on_compile_var/b.zig (100%) rename test/{cases => stage1/behavior}/namespace_depends_on_compile_var/index.zig (62%) rename test/{cases => stage1/behavior}/new_stack_call.zig (72%) rename test/{cases => stage1/behavior}/null.zig (80%) create mode 100644 test/stage1/behavior/optional.zig rename test/{cases => stage1/behavior}/pointers.zig (50%) create mode 100644 test/stage1/behavior/popcount.zig rename test/{cases => stage1/behavior}/ptrcast.zig (100%) rename test/{cases => stage1/behavior}/pub_enum/index.zig (54%) rename test/{cases => stage1/behavior}/pub_enum/other.zig (100%) rename test/{cases => stage1/behavior}/ref_var_in_if_after_if_2nd_switch_prong.zig (77%) create mode 100644 test/stage1/behavior/reflection.zig create mode 100644 test/stage1/behavior/sizeof_and_typeof.zig rename test/{cases => stage1/behavior}/slice.zig (62%) rename test/{cases => stage1/behavior}/struct.zig (64%) rename test/{cases => stage1/behavior}/struct_contains_null_ptr_itself.zig (81%) rename test/{cases => stage1/behavior}/struct_contains_slice_of_itself.zig (68%) rename test/{cases => stage1/behavior}/switch.zig (72%) rename test/{cases => stage1/behavior}/switch_prong_err_enum.zig (79%) rename test/{cases => stage1/behavior}/switch_prong_implicit_cast.zig (82%) rename test/{cases => stage1/behavior}/syntax.zig (99%) rename test/{cases => stage1/behavior}/this.zig (74%) rename test/{cases => stage1/behavior}/truncate.zig (65%) rename test/{cases => stage1/behavior}/try.zig (79%) create mode 100644 test/stage1/behavior/type_info.zig rename test/{cases => stage1/behavior}/undefined.zig (59%) rename test/{cases => stage1/behavior}/underscore.zig (91%) rename test/{cases => stage1/behavior}/union.zig (77%) rename test/{cases => stage1/behavior}/var_args.zig (56%) rename test/{cases => stage1/behavior}/void.zig (67%) rename test/{cases => stage1/behavior}/while.zig (83%) rename test/{cases => stage1/behavior}/widening.zig (75%) diff --git a/build.zig b/build.zig index 16185eebf4..d99165a6de 100644 --- a/build.zig +++ b/build.zig @@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void { } const modes = chosen_modes[0..chosen_mode_index]; - test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes)); + 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)); @@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { } else if (exe.target.isFreeBSD()) { try addCxxKnownPath(b, ctx, exe, "libc++.a", null); exe.linkSystemLibrary("pthread"); - } - else if (exe.target.isDarwin()) { + } else if (exe.target.isDarwin()) { if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { // Compiler is GCC. try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); diff --git a/doc/langref.html.in b/doc/langref.html.in index 6e03d3ec6d..909c0f5817 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4327,7 +4327,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {

For example, if we were to introduce another function to the above snippet:

- {#code_begin|test_err|unable to evaluate constant expression#} + {#code_begin|test_err|values of type 'type' must be comptime known#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } @@ -5905,13 +5905,13 @@ fn add(a: i32, b: i32) i32 { return a + b; } This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:

-
{#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
+
{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}

The optimizer is intelligent enough to turn the above snippet into a memcpy.

There is also a standard library function for this:

{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#} {#header_close#} {#header_open|@memset#} @@ -5923,7 +5923,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#} This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:

-
{#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
+
{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}

The optimizer is intelligent enough to turn the above snippet into a memset.

@@ -6592,9 +6592,10 @@ pub const TypeInfo = union(TypeId) { {#header_close#} {#header_open|@typeName#} -
{#syntax#}@typeName(T: type) []u8{#endsyntax#}
+
{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}

- This function returns the string representation of a type. + This function returns the string representation of a type, as + an array. It is equivalent to a string literal of the type name.

{#header_close#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 91b24e3110..4b134361a3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -56,9 +56,6 @@ struct IrExecutable { size_t next_debug_id; size_t *backward_branch_count; size_t backward_branch_quota; - bool invalid; - bool is_inline; - bool is_generic_instantiation; ZigFn *fn_entry; Buf *c_import_buf; AstNode *source_node; @@ -78,6 +75,10 @@ struct IrExecutable { IrBasicBlock *coro_suspend_block; IrBasicBlock *coro_final_cleanup_block; ZigVar *coro_allocator_var; + + bool invalid; + bool is_inline; + bool is_generic_instantiation; }; enum OutType { @@ -90,6 +91,9 @@ enum OutType { enum ConstParentId { ConstParentIdNone, ConstParentIdStruct, + ConstParentIdErrUnionCode, + ConstParentIdErrUnionPayload, + ConstParentIdOptionalPayload, ConstParentIdArray, ConstParentIdUnion, ConstParentIdScalar, @@ -107,6 +111,15 @@ struct ConstParent { ConstExprValue *struct_val; size_t field_index; } p_struct; + struct { + ConstExprValue *err_union_val; + } p_err_union_code; + struct { + ConstExprValue *err_union_val; + } p_err_union_payload; + struct { + ConstExprValue *optional_val; + } p_optional_payload; struct { ConstExprValue *union_val; } p_union; @@ -118,13 +131,11 @@ struct ConstParent { struct ConstStructValue { ConstExprValue *fields; - ConstParent parent; }; struct ConstUnionValue { BigInt tag; ConstExprValue *payload; - ConstParent parent; }; enum ConstArraySpecial { @@ -138,7 +149,6 @@ struct ConstArrayValue { union { struct { ConstExprValue *elements; - ConstParent parent; } s_none; Buf *s_buf; } data; @@ -153,19 +163,29 @@ enum ConstPtrSpecial { ConstPtrSpecialBaseArray, // The pointer points to a field in an underlying struct. ConstPtrSpecialBaseStruct, + // The pointer points to the error set field of an error union + ConstPtrSpecialBaseErrorUnionCode, + // The pointer points to the payload field of an error union + ConstPtrSpecialBaseErrorUnionPayload, + // The pointer points to the payload field of an optional + ConstPtrSpecialBaseOptionalPayload, // This means that we did a compile-time pointer reinterpret and we cannot // understand the value of pointee at compile time. However, we will still // emit a binary with a compile time known address. // In this case index is the numeric address value. - // We also use this for null pointer. We need the data layout for ConstCastOnly == true - // types to be the same, so all optionals of pointer types use x_ptr - // instead of x_optional ConstPtrSpecialHardCodedAddr, // This means that the pointer represents memory of assigning to _. // That is, storing discards the data, and loading is invalid. ConstPtrSpecialDiscard, // This is actually a function. ConstPtrSpecialFunction, + // This means the pointer is null. This is only allowed when the type is ?*T. + // We use this instead of ConstPtrSpecialHardCodedAddr because often we check + // for that value to avoid doing comptime work. + // We need the data layout for ConstCastOnly == true + // types to be the same, so all optionals of pointer types use x_ptr + // instead of x_optional. + ConstPtrSpecialNull, }; enum ConstPtrMut { @@ -199,6 +219,15 @@ struct ConstPtrValue { ConstExprValue *struct_val; size_t field_index; } base_struct; + struct { + ConstExprValue *err_union_val; + } base_err_union_code; + struct { + ConstExprValue *err_union_val; + } base_err_union_payload; + struct { + ConstExprValue *optional_val; + } base_optional_payload; struct { uint64_t addr; } hard_coded_addr; @@ -209,7 +238,7 @@ struct ConstPtrValue { }; struct ConstErrValue { - ErrorTableEntry *err; + ConstExprValue *error_set; ConstExprValue *payload; }; @@ -265,6 +294,7 @@ struct ConstGlobalRefs { struct ConstExprValue { ZigType *type; ConstValSpecial special; + ConstParent parent; ConstGlobalRefs *global_refs; union { @@ -433,7 +463,7 @@ enum NodeType { NodeTypeArrayType, NodeTypeErrorType, NodeTypeIfErrorExpr, - NodeTypeTestExpr, + NodeTypeIfOptional, NodeTypeErrorSetDecl, NodeTypeCancel, NodeTypeResume, @@ -677,7 +707,7 @@ struct AstNodeUse { AstNode *expr; TldResolution resolution; - IrInstruction *value; + ConstExprValue *value; }; struct AstNodeIfBoolExpr { @@ -1610,7 +1640,7 @@ struct CodeGen { HashMap fn_type_table; HashMap error_table; HashMap generic_table; - HashMap memoized_fn_eval_table; + HashMap memoized_fn_eval_table; HashMap llvm_fn_table; HashMap exported_symbol_names; HashMap external_prototypes; @@ -1802,10 +1832,9 @@ enum VarLinkage { struct ZigVar { Buf name; - ConstExprValue *value; + ConstExprValue *const_value; + ZigType *var_type; LLVMValueRef value_ref; - bool src_is_const; - bool gen_is_const; IrInstruction *is_comptime; // which node is the declaration of the variable AstNode *decl_node; @@ -1815,17 +1844,21 @@ struct ZigVar { Scope *parent_scope; Scope *child_scope; LLVMValueRef param_value_ref; - bool shadowable; size_t mem_slot_index; IrExecutable *owner_exec; size_t ref_count; - VarLinkage linkage; - uint32_t align_bytes; // In an inline loop, multiple variables may be created, // In this case, a reference to a variable should follow // this pointer to the redefined variable. ZigVar *next_var; + + uint32_t align_bytes; + VarLinkage linkage; + + bool shadowable; + bool src_is_const; + bool gen_is_const; }; struct ErrorTableEntry { @@ -1891,10 +1924,11 @@ struct ScopeBlock { ZigList *incoming_values; ZigList *incoming_blocks; - bool safety_off; AstNode *safety_set_node; - bool fast_math_on; AstNode *fast_math_set_node; + + bool safety_off; + bool fast_math_on; }; // This scope is created from every defer expression. @@ -2030,8 +2064,19 @@ struct IrBasicBlock { IrInstruction *must_be_comptime_source_instr; }; +// These instructions are in transition to having "pass 1" instructions +// and "pass 2" instructions. The pass 1 instructions are suffixed with Src +// and pass 2 are suffixed with Gen. +// Once all instructions are separated in this way, they'll have different +// base types for better type safety. +// Src instructions are generated by ir_gen_* functions in ir.cpp from AST. +// ir_analyze_* functions consume Src instructions and produce Gen instructions. +// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. +// Src instructions do not have type information; Gen instructions do. enum IrInstructionId { IrInstructionIdInvalid, + IrInstructionIdDeclVarSrc, + IrInstructionIdDeclVarGen, IrInstructionIdBr, IrInstructionIdCondBr, IrInstructionIdSwitchBr, @@ -2040,7 +2085,6 @@ enum IrInstructionId { IrInstructionIdPhi, IrInstructionIdUnOp, IrInstructionIdBinOp, - IrInstructionIdDeclVar, IrInstructionIdLoadPtr, IrInstructionIdStorePtr, IrInstructionIdFieldPtr, @@ -2069,7 +2113,7 @@ enum IrInstructionId { IrInstructionIdAsm, IrInstructionIdSizeOf, IrInstructionIdTestNonNull, - IrInstructionIdUnwrapOptional, + IrInstructionIdOptionalUnwrapPtr, IrInstructionIdOptionalWrap, IrInstructionIdUnionTag, IrInstructionIdClz, @@ -2085,7 +2129,8 @@ enum IrInstructionId { IrInstructionIdCompileLog, IrInstructionIdErrName, IrInstructionIdEmbedFile, - IrInstructionIdCmpxchg, + IrInstructionIdCmpxchgSrc, + IrInstructionIdCmpxchgGen, IrInstructionIdFence, IrInstructionIdTruncate, IrInstructionIdIntCast, @@ -2114,7 +2159,8 @@ enum IrInstructionId { IrInstructionIdErrWrapPayload, IrInstructionIdFnProto, IrInstructionIdTestComptime, - IrInstructionIdPtrCast, + IrInstructionIdPtrCastSrc, + IrInstructionIdPtrCastGen, IrInstructionIdBitCast, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -2194,6 +2240,22 @@ struct IrInstruction { bool is_gen; }; +struct IrInstructionDeclVarSrc { + IrInstruction base; + + ZigVar *var; + IrInstruction *var_type; + IrInstruction *align_value; + IrInstruction *init_value; +}; + +struct IrInstructionDeclVarGen { + IrInstruction base; + + ZigVar *var; + IrInstruction *init_value; +}; + struct IrInstructionCondBr { IrInstruction base; @@ -2302,20 +2364,11 @@ struct IrInstructionBinOp { IrInstruction base; IrInstruction *op1; - IrBinOp op_id; IrInstruction *op2; + IrBinOp op_id; bool safety_check_on; }; -struct IrInstructionDeclVar { - IrInstruction base; - - ZigVar *var; - IrInstruction *var_type; - IrInstruction *align_value; - IrInstruction *init_value; -}; - struct IrInstructionLoadPtr { IrInstruction base; @@ -2335,7 +2388,6 @@ struct IrInstructionFieldPtr { IrInstruction *container_ptr; Buf *field_name_buffer; IrInstruction *field_name_expr; - bool is_const; }; struct IrInstructionStructFieldPtr { @@ -2378,13 +2430,13 @@ struct IrInstructionCall { ZigFn *fn_entry; size_t arg_count; IrInstruction **args; - bool is_comptime; LLVMValueRef tmp_ptr; - FnInline fn_inline; - bool is_async; IrInstruction *async_allocator; IrInstruction *new_stack; + FnInline fn_inline; + bool is_async; + bool is_comptime; }; struct IrInstructionConst { @@ -2527,9 +2579,9 @@ struct IrInstructionSliceType { IrInstruction base; IrInstruction *align_value; + IrInstruction *child_type; bool is_const; bool is_volatile; - IrInstruction *child_type; }; struct IrInstructionAsm { @@ -2557,10 +2609,12 @@ struct IrInstructionTestNonNull { IrInstruction *value; }; -struct IrInstructionUnwrapOptional { +// Takes a pointer to an optional value, returns a pointer +// to the payload. +struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *value; + IrInstruction *base_ptr; bool safety_check_on; }; @@ -2651,7 +2705,7 @@ struct IrInstructionEmbedFile { IrInstruction *name; }; -struct IrInstructionCmpxchg { +struct IrInstructionCmpxchgSrc { IrInstruction base; IrInstruction *type_value; @@ -2661,14 +2715,19 @@ struct IrInstructionCmpxchg { IrInstruction *success_order_value; IrInstruction *failure_order_value; - // if this instruction gets to runtime then we know these values: - ZigType *type; + bool is_weak; +}; + +struct IrInstructionCmpxchgGen { + IrInstruction base; + + IrInstruction *ptr; + IrInstruction *cmp_value; + IrInstruction *new_value; + LLVMValueRef tmp_ptr; AtomicOrder success_order; AtomicOrder failure_order; - bool is_weak; - - LLVMValueRef tmp_ptr; }; struct IrInstructionFence { @@ -2851,7 +2910,7 @@ struct IrInstructionTestErr { struct IrInstructionUnwrapErrCode { IrInstruction base; - IrInstruction *value; + IrInstruction *err_union; }; struct IrInstructionUnwrapErrPayload { @@ -2899,13 +2958,19 @@ struct IrInstructionTestComptime { IrInstruction *value; }; -struct IrInstructionPtrCast { +struct IrInstructionPtrCastSrc { IrInstruction base; IrInstruction *dest_type; IrInstruction *ptr; }; +struct IrInstructionPtrCastGen { + IrInstruction base; + + IrInstruction *ptr; +}; + struct IrInstructionBitCast { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 15370983fc..194888068c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -570,7 +570,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)) { + } else if (type_is_codegen_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 @@ -1278,7 +1278,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { +static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name) +{ size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, @@ -1286,12 +1288,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); + if (type_is_invalid(result->type)) return g->builtin_types.entry_invalid; - assert(result->value.special != ConstValSpecialRuntime); - return result->value.data.x_type; + assert(result->special != ConstValSpecialRuntime); + return result->data.x_type; } ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { @@ -1342,11 +1344,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou } static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); - if (type_is_invalid(align_result->value.type)) + ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); + if (type_is_invalid(align_result->type)) return false; - uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); + uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint); if (align_bytes == 0) { add_node_error(g, node, buf_sprintf("alignment must be >= 1")); return false; @@ -1364,12 +1366,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(g, ptr_type); - IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); - if (type_is_invalid(instr->value.type)) + ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); + if (type_is_invalid(result_val->type)) return false; - ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; - ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; + ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index]; assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; @@ -2504,20 +2506,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { // In this first pass we resolve explicit tag values. // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { enum_type->data.enumeration.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt || - result_inst->value.type->id == ZigTypeIdComptimeInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt || + result->type->id == ZigTypeIdComptimeInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -2944,19 +2946,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { union_type->data.unionation.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -3419,7 +3421,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { resolve_top_level_decl(g, tld, false, tld->source_node); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - tld_var->var->value = value; + tld_var->var->const_value = value; + tld_var->var->var_type = value->type; tld_var->var->align_bytes = get_abi_alignment(g, value->type); } @@ -3513,7 +3516,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeArrayType: case NodeTypeErrorType: case NodeTypeIfErrorExpr: - case NodeTypeTestExpr: + case NodeTypeIfOptional: case NodeTypeErrorSetDecl: case NodeTypeCancel: case NodeTypeResume: @@ -3582,13 +3585,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry // Set name to nullptr to make the variable anonymous (not visible to programmer). // TODO merge with definition of add_local_var in ir.cpp ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ConstExprValue *value, Tld *src_tld) + bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type) { Error err; - assert(value); + assert(const_value != nullptr); + assert(var_type != nullptr); ZigVar *variable_entry = allocate(1); - variable_entry->value = value; + variable_entry->const_value = const_value; + variable_entry->var_type = var_type; variable_entry->parent_scope = parent_scope; variable_entry->shadowable = false; variable_entry->mem_slot_index = SIZE_MAX; @@ -3597,23 +3602,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf assert(name); buf_init_from_buf(&variable_entry->name, name); - if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) { - variable_entry->value->type = g->builtin_types.entry_invalid; + if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { + variable_entry->var_type = g->builtin_types.entry_invalid; } else { - variable_entry->align_bytes = get_abi_alignment(g, value->type); + variable_entry->align_bytes = get_abi_alignment(g, var_type); ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); if (existing_var && !existing_var->shadowable) { ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { ZigType *type; if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { add_node_error(g, source_node, buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { Scope *search_scope = nullptr; if (src_tld == nullptr) { @@ -3627,7 +3632,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } } } @@ -3677,7 +3682,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { linkage = VarLinkageInternal; } - IrInstruction *init_value = nullptr; + ConstExprValue *init_value = nullptr; // TODO more validation for types that can't be used for export/extern variables ZigType *implicit_type = nullptr; @@ -3686,7 +3691,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } else if (var_decl->expr) { init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); assert(init_value); - implicit_type = init_value->value.type; + implicit_type = init_value->type; if (implicit_type->id == ZigTypeIdUnreachable) { add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); @@ -3704,7 +3709,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); implicit_type = g->builtin_types.entry_invalid; } - assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime); + assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); } else if (linkage != VarLinkageExternal) { add_node_error(g, source_node, buf_sprintf("variables must be initialized")); implicit_type = g->builtin_types.entry_invalid; @@ -3713,19 +3718,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { ZigType *type = explicit_type ? explicit_type : implicit_type; assert(type != nullptr); // should have been caught by the parser - ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type); + ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type); tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, - is_const, init_val, &tld_var->base); + is_const, init_val, &tld_var->base, type); tld_var->var->linkage = linkage; if (implicit_type != nullptr && type_is_invalid(implicit_type)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } if (var_decl->align_expr != nullptr) { if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } } @@ -4090,7 +4095,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { } ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_name, true, create_const_runtime(param_type), nullptr); + param_name, true, create_const_runtime(param_type), nullptr, param_type); var->src_arg_index = i; fn_table_entry->child_scope = var->child_scope; var->shadowable = var->shadowable || is_var_args; @@ -4228,18 +4233,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * preview_use_decl(g, src_use_node); } - IrInstruction *use_target_value = src_use_node->data.use.value; - if (use_target_value->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *use_target_value = src_use_node->data.use.value; + if (type_is_invalid(use_target_value->type)) { dst_use_node->owner->any_imports_failed = true; return; } dst_use_node->data.use.resolution = TldResolutionOk; - ConstExprValue *const_val = &use_target_value->value; - assert(const_val->special != ConstValSpecialRuntime); + assert(use_target_value->special != ConstValSpecialRuntime); - ImportTableEntry *target_import = const_val->data.x_import; + ImportTableEntry *target_import = use_target_value->data.x_import; assert(target_import); if (target_import->any_imports_failed) { @@ -4302,10 +4306,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { } node->data.use.resolution = TldResolutionResolving; - IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, + ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base, node->data.use.expr, g->builtin_types.entry_namespace, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + if (type_is_invalid(result->type)) node->owner->any_imports_failed = true; node->data.use.value = result; @@ -4486,7 +4490,8 @@ 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_codegen_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); if (type_entry->data.unionation.gen_field_count == 0) @@ -4732,6 +4737,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } +static uint32_t hash_const_val_error_set(ConstExprValue *const_val) { + assert(const_val->data.x_err_set != nullptr); + return const_val->data.x_err_set->value ^ 2630160122; +} + static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { uint32_t hash_val = 0; switch (const_val->data.x_ptr.mut) { @@ -4763,6 +4773,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); return hash_val; + case ConstPtrSpecialBaseErrorUnionCode: + hash_val += (uint32_t)2994743799; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val); + return hash_val; + case ConstPtrSpecialBaseErrorUnionPayload: + hash_val += (uint32_t)3456080131; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val); + return hash_val; + case ConstPtrSpecialBaseOptionalPayload: + hash_val += (uint32_t)3163140517; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val); + return hash_val; case ConstPtrSpecialHardCodedAddr: hash_val += (uint32_t)4048518294; hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); @@ -4774,6 +4796,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += (uint32_t)2590901619; hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); return hash_val; + case ConstPtrSpecialNull: + hash_val += (uint32_t)1486246455; + return hash_val; } zig_unreachable(); } @@ -4872,7 +4897,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return 2709806591; case ZigTypeIdOptional: if (get_codegen_ptr_type(const_val->type) != nullptr) { - return hash_const_val(const_val) * 1992916303; + return hash_const_val_ptr(const_val) * 1992916303; + } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { + return hash_const_val_error_set(const_val) * 3147031929; } else { if (const_val->data.x_optional) { return hash_const_val(const_val->data.x_optional) * 1992916303; @@ -4884,8 +4911,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { // TODO better hashing algorithm return 3415065496; case ZigTypeIdErrorSet: - assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set->value ^ 2630160122; + return hash_const_val_error_set(const_val); case ZigTypeIdNamespace: return hash_ptr(const_val->data.x_import); case ZigTypeIdBoundFn: @@ -4987,7 +5013,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { return can_mutate_comptime_var_state(value->data.x_optional); case ZigTypeIdErrorUnion: - if (value->data.x_err_union.err != nullptr) + if (value->data.x_err_union.error_set->data.x_err_set != nullptr) return false; assert(value->data.x_err_union.payload != nullptr); return can_mutate_comptime_var_state(value->data.x_err_union.payload); @@ -5048,9 +5074,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (type_is_invalid(var_scope->var->value->type)) + if (type_is_invalid(var_scope->var->var_type)) return false; - if (can_mutate_comptime_var_state(var_scope->var->value)) + if (can_mutate_comptime_var_state(var_scope->var->const_value)) return false; } else if (scope->id == ScopeIdFnDef) { return true; @@ -5068,7 +5094,7 @@ uint32_t fn_eval_hash(Scope* scope) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - result += hash_const_val(var_scope->var->value); + result += hash_const_val(var_scope->var->const_value); } else if (scope->id == ScopeIdFnDef) { ScopeFnDef *fn_scope = (ScopeFnDef *)scope; result += hash_ptr(fn_scope->fn_entry); @@ -5092,10 +5118,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { if (a->id == ScopeIdVarDecl) { ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; - if (a_var_scope->var->value->type != b_var_scope->var->value->type) - return false; - if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value)) + if (a_var_scope->var->var_type != b_var_scope->var->var_type) return false; + if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && + b_var_scope->var->var_type == b_var_scope->var->const_value->type) + { + if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) + return false; + } else { + zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); + } } else if (a->id == ScopeIdFnDef) { ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; @@ -5113,6 +5145,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { return false; } +// Whether the type has bits at runtime. bool type_has_bits(ZigType *type_entry) { assert(type_entry); assert(!type_is_invalid(type_entry)); @@ -5120,6 +5153,65 @@ bool type_has_bits(ZigType *type_entry) { return !type_entry->zero_bits; } +// Whether you can infer the value based solely on the type. +OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { + assert(type_entry != nullptr); + Error err; + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return OnePossibleValueInvalid; + switch (type_entry->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdOpaque: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdMetaType: + case ZigTypeIdNamespace: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdOptional: + case ZigTypeIdFn: + case ZigTypeIdBool: + case ZigTypeIdFloat: + case ZigTypeIdPromise: + case ZigTypeIdErrorUnion: + return OnePossibleValueNo; + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdVoid: + case ZigTypeIdUnreachable: + return OnePossibleValueYes; + case ZigTypeIdArray: + if (type_entry->data.array.len == 0) + return OnePossibleValueYes; + return type_has_one_possible_value(g, type_entry->data.array.child_type); + case ZigTypeIdStruct: + for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { + TypeStructField *field = &type_entry->data.structure.fields[i]; + switch (type_has_one_possible_value(g, field->type_entry)) { + case OnePossibleValueInvalid: + return OnePossibleValueInvalid; + case OnePossibleValueNo: + return OnePossibleValueNo; + case OnePossibleValueYes: + continue; + } + } + return OnePossibleValueYes; + case ZigTypeIdErrorSet: + case ZigTypeIdEnum: + case ZigTypeIdInt: + return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; + case ZigTypeIdPointer: + return type_has_one_possible_value(g, type_entry->data.pointer.child_type); + case ZigTypeIdUnion: + if (type_entry->data.unionation.src_field_count > 1) + return OnePossibleValueNo; + return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); + } + zig_unreachable(); +} + ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { Error err; if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) @@ -5574,6 +5666,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) return false; return true; + case ConstPtrSpecialBaseErrorUnionCode: + if (a->data.x_ptr.data.base_err_union_code.err_union_val != + b->data.x_ptr.data.base_err_union_code.err_union_val && + a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseErrorUnionPayload: + if (a->data.x_ptr.data.base_err_union_payload.err_union_val != + b->data.x_ptr.data.base_err_union_payload.err_union_val && + a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseOptionalPayload: + if (a->data.x_ptr.data.base_optional_payload.optional_val != + b->data.x_ptr.data.base_optional_payload.optional_val && + a->data.x_ptr.data.base_optional_payload.optional_val->global_refs != + b->data.x_ptr.data.base_optional_payload.optional_val->global_refs) + { + return false; + } + return true; case ConstPtrSpecialHardCodedAddr: if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) return false; @@ -5582,6 +5701,8 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { return true; case ConstPtrSpecialFunction: return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; + case ConstPtrSpecialNull: + return true; } zig_unreachable(); } @@ -5750,7 +5871,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v } } -void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { +static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { assert(type_entry->id == ZigTypeIdPointer); if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { @@ -5763,6 +5884,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy zig_unreachable(); case ConstPtrSpecialRef: case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialBaseErrorUnionCode: + case ConstPtrSpecialBaseErrorUnionPayload: + case ConstPtrSpecialBaseOptionalPayload: buf_appendf(buf, "*"); // TODO we need a source node for const_ptr_pointee because it can generate compile errors render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); @@ -5790,10 +5914,21 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); return; } + case ConstPtrSpecialNull: + buf_append_str(buf, "null"); + return; } zig_unreachable(); } +static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { + if (const_val->data.x_err_set == nullptr) { + buf_append_str(buf, "null"); + } else { + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); + } +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -5921,6 +6056,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { { if (get_codegen_ptr_type(const_val->type) != nullptr) return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); + if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) + return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); if (const_val->data.x_optional) { render_const_value(g, buf, const_val->data.x_optional); } else { @@ -5958,11 +6095,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdErrorUnion: { buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); - if (const_val->data.x_err_union.err == nullptr) { + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + if (err_set == nullptr) { render_const_value(g, buf, const_val->data.x_err_union.payload); } else { buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), - buf_ptr(&const_val->data.x_err_union.err->name)); + buf_ptr(&err_set->name)); } buf_appendf(buf, ")"); return; @@ -5977,10 +6115,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case ZigTypeIdErrorSet: - { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); - return; - } + return render_const_val_err_set(g, buf, const_val, type_entry); case ZigTypeIdArgTuple: { buf_appendf(buf, "(args value)"); @@ -6172,6 +6307,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { assert(const_val->type->id == ZigTypeIdArray); + if (const_val->special == ConstValSpecialUndef) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.special = ConstArraySpecialUndef; + } switch (const_val->data.x_array.special) { case ConstArraySpecialNone: return; @@ -6215,17 +6354,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { } ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { - assert(value->type); - ZigType *type_entry = value->type; - if (type_entry->id == ZigTypeIdArray) { - expand_undef_array(g, value); - return &value->data.x_array.data.s_none.parent; - } else if (type_entry->id == ZigTypeIdStruct) { - return &value->data.x_struct.parent; - } else if (type_entry->id == ZigTypeIdUnion) { - return &value->data.x_union.parent; - } - return nullptr; + return &value->parent; } static const ZigTypeId all_type_ids[] = { @@ -6453,7 +6582,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { resolve_top_level_decl(codegen, tld, false, nullptr); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - ConstExprValue *var_value = tld_var->var->value; + ConstExprValue *var_value = tld_var->var->const_value; assert(var_value != nullptr); return var_value; } diff --git a/src/analyze.hpp b/src/analyze.hpp index efbc065a63..1bac15ebcc 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -81,7 +81,7 @@ ZigFn *scope_fn_entry(Scope *scope); ImportTableEntry *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); + bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); ZigFn *create_fn(CodeGen *g, AstNode *proto_node); ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); @@ -222,6 +222,13 @@ enum ReqCompTime { }; ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); +enum OnePossibleValue { + OnePossibleValueInvalid, + OnePossibleValueNo, + OnePossibleValueYes, +}; +OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); + Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *const_val, ZigType *wanted_type); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index f7eb646e16..994ba5f5b1 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) { return "ErrorType"; case NodeTypeIfErrorExpr: return "IfErrorExpr"; - case NodeTypeTestExpr: - return "TestExpr"; + case NodeTypeIfOptional: + return "IfOptional"; case NodeTypeErrorSetDecl: return "ErrorSetDecl"; case NodeTypeCancel: @@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { if (node->data.if_err_expr.else_node) return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); return node->data.if_err_expr.then_node->type == NodeTypeBlock; - case NodeTypeTestExpr: + case NodeTypeIfOptional: if (node->data.test_expr.else_node) return statement_terminates_without_semicolon(node->data.test_expr.else_node); return node->data.test_expr.then_node->type == NodeTypeBlock; @@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } break; } - case NodeTypeTestExpr: + case NodeTypeIfOptional: { fprintf(ar->f, "if ("); render_node_grouped(ar, node->data.test_expr.target_node); diff --git a/src/codegen.cpp b/src/codegen.cpp index 47f2aa103f..2f360735dd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -313,6 +313,8 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char * static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name); static void generate_error_name_table(CodeGen *g); +static bool value_is_all_undef(ConstExprValue *const_val); +static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr); static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); @@ -461,6 +463,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag } } +static bool cc_want_sret_attr(CallingConvention cc) { + switch (cc) { + case CallingConventionNaked: + zig_unreachable(); + case CallingConventionC: + case CallingConventionCold: + case CallingConventionStdcall: + return true; + case CallingConventionAsync: + case CallingConventionUnspecified: + return false; + } + zig_unreachable(); +} + static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { if (fn_table_entry->llvm_value) return fn_table_entry->llvm_value; @@ -598,9 +615,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { } else if (type_is_codegen_pointer(return_type)) { addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { - addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); - if (cc == CallingConventionC) { + addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); + if (cc_want_sret_attr(cc)) { addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias"); } init_gen_i = 1; @@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { assert(variable); assert(variable->value_ref); - if (!handle_is_ptr(variable->value->type)) { + if (!handle_is_ptr(variable->var_type)) { clear_debug_source_node(g); - gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref, - variable->align_bytes, false); + gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), + variable->value_ref, variable->align_bytes, false); } if (variable->decl_node) { @@ -2961,7 +2978,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, } static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, - IrInstructionPtrCast *instruction) + IrInstructionPtrCastGen *instruction) { ZigType *wanted_type = instruction->base.value.type; if (!type_has_bits(wanted_type)) { @@ -3149,11 +3166,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI } static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, - IrInstructionDeclVar *decl_var_instruction) + IrInstructionDeclVarGen *decl_var_instruction) { ZigVar *var = decl_var_instruction->var; - if (!type_has_bits(var->value->type)) + if (!type_has_bits(var->var_type)) return nullptr; if (var->ref_count == 0 && g->build_mode != BuildModeDebug) @@ -3161,34 +3178,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstruction *init_value = decl_var_instruction->init_value; - bool have_init_expr = false; - - ConstExprValue *const_val = &init_value->value; - if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) - have_init_expr = true; + bool have_init_expr = !value_is_all_undef(&init_value->value); if (have_init_expr) { - assert(var->value->type == init_value->value.type); - ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, + ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, PtrLenSingle, var->align_bytes, 0, 0); LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); - } else { - bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); - if (want_safe) { - ZigType *usize = g->builtin_types.entry_usize; - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref); - assert(size_bytes > 0); - - assert(var->align_bytes > 0); - - // memset uninitialized memory to 0xa - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, ""); - LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); - ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false); - } + } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { + uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes; + gen_undef_init(g, align_bytes, var->var_type, var->value_ref); } gen_var_debug_decl(g, var); @@ -3225,21 +3224,75 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); } +static bool value_is_all_undef(ConstExprValue *const_val) { + switch (const_val->special) { + case ConstValSpecialRuntime: + return false; + case ConstValSpecialUndef: + return true; + case ConstValSpecialStatic: + if (const_val->type->id == ZigTypeIdStruct) { + for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { + if (!value_is_all_undef(&const_val->data.x_struct.fields[i])) + return false; + } + return true; + } else if (const_val->type->id == ZigTypeIdArray) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return true; + case ConstArraySpecialBuf: + return false; + case ConstArraySpecialNone: + for (size_t i = 0; i < const_val->type->data.array.len; i += 1) { + if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) + return false; + } + return true; + } + zig_unreachable(); + } else { + return false; + } + } + zig_unreachable(); +} + +static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) { + assert(type_has_bits(value_type)); + uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref); + assert(size_bytes > 0); + assert(ptr_align_bytes > 0); + // memset uninitialized memory to 0xaa + LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); + LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); + LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); + ZigType *usize = g->builtin_types.entry_usize; + LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); + ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); +} + static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - assert(instruction->ptr->value.type->id == ZigTypeIdPointer); ZigType *ptr_type = instruction->ptr->value.type; + assert(ptr_type->id == ZigTypeIdPointer); + if (!type_has_bits(ptr_type)) + return nullptr; - gen_assign_raw(g, ptr, ptr_type, value); - + bool have_init_expr = !value_is_all_undef(&instruction->value->value); + if (have_init_expr) { + LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); + LLVMValueRef value = ir_llvm_value(g, instruction->value); + gen_assign_raw(g, ptr, ptr_type, value); + } else if (ir_want_runtime_safety(g, &instruction->base)) { + gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type, + ir_llvm_value(g, instruction->ptr)); + } return nullptr; } static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { ZigVar *var = instruction->var; - if (type_has_bits(var->value->type)) { + if (type_has_bits(var->var_type)) { assert(var->value_ref); return var->value_ref; } else { @@ -3553,7 +3606,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMPositionBuilderAtEnd(g->builder, ok_block); } - LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, ""); + LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, + union_type->data.unionation.gen_union_index, ""); LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); return bitcasted_union_field_ptr; } @@ -3715,8 +3769,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR if (child_type->zero_bits) { return maybe_handle; } else { - bool maybe_is_ptr = type_is_codegen_pointer(child_type); - if (maybe_is_ptr) { + bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; + if (is_scalar) { return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); } else { LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); @@ -3731,17 +3785,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value)); } -static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, - IrInstructionUnwrapOptional *instruction) +static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionOptionalUnwrapPtr *instruction) { - ZigType *ptr_type = instruction->value->value.type; + ZigType *ptr_type = instruction->base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); - LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); + LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { + LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); @@ -3755,8 +3809,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, if (child_type->zero_bits) { return nullptr; } else { - bool maybe_is_ptr = type_is_codegen_pointer(child_type); - if (maybe_is_ptr) { + bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; + if (is_scalar) { return maybe_ptr; } else { LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); @@ -4174,7 +4228,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) zig_unreachable(); } -static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) { +static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) { LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); @@ -4189,18 +4243,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - if (type_is_codegen_pointer(child_type)) { + if (!handle_is_ptr(maybe_type)) { LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); } assert(instruction->tmp_ptr != nullptr); - assert(type_has_bits(instruction->type)); + assert(type_has_bits(child_type)); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val); + gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); @@ -4351,6 +4405,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst assert(array_type->data.structure.is_slice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); + assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index; assert(ptr_index != SIZE_MAX); @@ -4540,12 +4595,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); } -static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { - ZigType *ptr_type = instruction->value->value.type; +static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, + IrInstructionUnwrapErrCode *instruction) +{ + ZigType *ptr_type = instruction->err_union->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union); LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); if (type_has_bits(payload_type)) { @@ -4556,7 +4613,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab } } -static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { +static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, + IrInstructionUnwrapErrPayload *instruction) +{ + bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && + g->errors_by_index.length > 1; + if (!want_safety && !type_has_bits(instruction->base.value.type)) + return nullptr; ZigType *ptr_type = instruction->value->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; @@ -4568,7 +4631,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu return err_union_handle; } - if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { + if (want_safety) { LLVMValueRef err_val; if (type_has_bits(payload_type)) { LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); @@ -4607,7 +4670,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)) { + if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { return payload_val; } @@ -5184,12 +5247,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: case IrInstructionIdCheckRuntimeScope: + case IrInstructionIdDeclVarSrc: + case IrInstructionIdPtrCastSrc: + case IrInstructionIdCmpxchgSrc: zig_unreachable(); + case IrInstructionIdDeclVarGen: + return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); - case IrInstructionIdDeclVar: - return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction); case IrInstructionIdBinOp: return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction); case IrInstructionIdCast: @@ -5220,8 +5286,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); case IrInstructionIdTestNonNull: return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapOptional: - return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction); case IrInstructionIdClz: return ir_render_clz(g, executable, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -5236,8 +5302,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_ref(g, executable, (IrInstructionRef *)instruction); case IrInstructionIdErrName: return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); - case IrInstructionIdCmpxchg: - return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgGen: + return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction); case IrInstructionIdFence: return ir_render_fence(g, executable, (IrInstructionFence *)instruction); case IrInstructionIdTruncate: @@ -5278,8 +5344,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdUnionInit: return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); - case IrInstructionIdPtrCast: - return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastGen: + return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); case IrInstructionIdBitCast: return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); case IrInstructionIdWidenOrShorten: @@ -5377,6 +5443,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val); +static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val); +static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val); +static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val); static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { switch (parent->id) { @@ -5387,6 +5456,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent case ConstParentIdStruct: return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, parent->data.p_struct.field_index); + case ConstParentIdErrUnionCode: + return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val); + case ConstParentIdErrUnionPayload: + return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val); + case ConstParentIdOptionalPayload: + return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val); case ConstParentIdArray: return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, parent->data.p_array.elem_index); @@ -5402,7 +5477,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { expand_undef_array(g, array_const_val); - ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent; + ConstParent *parent = &array_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); @@ -5427,7 +5502,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar } static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { - ConstParent *parent = &struct_const_val->data.x_struct.parent; + ConstParent *parent = &struct_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); ZigType *u32 = g->builtin_types.entry_u32; @@ -5438,8 +5513,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s return LLVMConstInBoundsGEP(base_ptr, indices, 2); } +static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { + ConstParent *parent = &err_union_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, err_union_err_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + +static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { + ConstParent *parent = &err_union_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, err_union_payload_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + +static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) { + ConstParent *parent = &optional_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, maybe_child_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { - ConstParent *parent = &union_const_val->data.x_union.parent; + ConstParent *parent = &union_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); ZigType *u32 = g->builtin_types.entry_u32; @@ -5609,6 +5720,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con render_const_val_global(g, const_val, ""); return ptr_val; } + case ConstPtrSpecialBaseErrorUnionCode: + { + render_const_val_global(g, const_val, name); + ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; + assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); + if (err_union_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseErrorUnionPayload: + { + render_const_val_global(g, const_val, name); + ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; + assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); + if (err_union_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseOptionalPayload: + { + render_const_val_global(g, const_val, name); + ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; + assert(optional_const_val->type->id == ZigTypeIdOptional); + if (optional_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } case ConstPtrSpecialHardCodedAddr: { render_const_val_global(g, const_val, name); @@ -5621,10 +5789,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con } case ConstPtrSpecialFunction: return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); + case ConstPtrSpecialNull: + return LLVMConstNull(const_val->type->type_ref); } zig_unreachable(); } +static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) { + uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value; + return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false); +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { Error err; @@ -5644,9 +5819,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c case ZigTypeIdInt: return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); case ZigTypeIdErrorSet: - assert(const_val->data.x_err_set != nullptr); - return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, - const_val->data.x_err_set->value, false); + return gen_const_val_err_set(g, const_val, name); case ZigTypeIdFloat: switch (type_entry->data.floating.bit_count) { case 16: @@ -5680,6 +5853,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); } else if (type_is_codegen_pointer(child_type)) { 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); } else { LLVMValueRef child_val; LLVMValueRef maybe_val; @@ -5914,7 +6089,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c ZigType *err_set_type = type_entry->data.error_union.err_set_type; if (!type_has_bits(payload_type)) { assert(type_has_bits(err_set_type)); - uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + uint64_t value = (err_set == nullptr) ? 0 : err_set->value; return LLVMConstInt(g->err_tag_type->type_ref, value, false); } else if (!type_has_bits(err_set_type)) { assert(type_has_bits(payload_type)); @@ -5923,8 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c LLVMValueRef err_tag_value; LLVMValueRef err_payload_value; bool make_unnamed_struct; - if (const_val->data.x_err_union.err) { - err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + if (err_set != nullptr) { + err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false); err_payload_value = LLVMConstNull(payload_type->type_ref); make_unnamed_struct = false; } else { @@ -6130,10 +6307,13 @@ static void do_code_gen(CodeGen *g) { TldVar *tld_var = g->global_vars.at(i); ZigVar *var = tld_var->var; - if (var->value->type->id == ZigTypeIdComptimeFloat) { + if (var->var_type->id == ZigTypeIdComptimeFloat) { // Generate debug info for it but that's it. - ConstExprValue *const_val = var->value; + ConstExprValue *const_val = var->const_value; assert(const_val->special != ConstValSpecialRuntime); + if (const_val->type != var->var_type) { + zig_panic("TODO debug info for var with ptr casted value"); + } ZigType *var_type = g->builtin_types.entry_f128; ConstExprValue coerced_value; coerced_value.special = ConstValSpecialStatic; @@ -6144,10 +6324,13 @@ static void do_code_gen(CodeGen *g) { continue; } - if (var->value->type->id == ZigTypeIdComptimeInt) { + if (var->var_type->id == ZigTypeIdComptimeInt) { // Generate debug info for it but that's it. - ConstExprValue *const_val = var->value; + ConstExprValue *const_val = var->const_value; assert(const_val->special != ConstValSpecialRuntime); + if (const_val->type != var->var_type) { + zig_panic("TODO debug info for var with ptr casted value"); + } size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); if (bits_needed < 8) { bits_needed = 8; @@ -6158,7 +6341,7 @@ static void do_code_gen(CodeGen *g) { continue; } - if (!type_has_bits(var->value->type)) + if (!type_has_bits(var->var_type)) continue; assert(var->decl_node); @@ -6167,9 +6350,9 @@ static void do_code_gen(CodeGen *g) { if (var->linkage == VarLinkageExternal) { LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); if (existing_llvm_var) { - global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0)); + global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0)); } else { - global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name)); + global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name)); // TODO debug info for the extern variable LLVMSetLinkage(global_value, LLVMExternalLinkage); @@ -6180,9 +6363,9 @@ static void do_code_gen(CodeGen *g) { } else { bool exported = (var->linkage == VarLinkageExport); const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); - render_const_val(g, var->value, mangled_name); - render_const_val_global(g, var->value, mangled_name); - global_value = var->value->global_refs->llvm_global; + render_const_val(g, var->const_value, mangled_name); + render_const_val_global(g, var->const_value, mangled_name); + global_value = var->const_value->global_refs->llvm_global; if (exported) { LLVMSetLinkage(global_value, LLVMExternalLinkage); @@ -6194,8 +6377,10 @@ static void do_code_gen(CodeGen *g) { LLVMSetAlignment(global_value, var->align_bytes); // TODO debug info for function pointers - if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) { - gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type); + // Here we use const_value->type because that's the type of the llvm global, + // which we const ptr cast upon use to whatever it needs to be. + if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) { + gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type); } LLVMSetGlobalConstant(global_value, var->gen_is_const); @@ -6281,8 +6466,8 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdErrWrapCode) { IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; slot = &err_wrap_code_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdCmpxchg) { - IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction; + } else if (instruction->id == IrInstructionIdCmpxchgGen) { + IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; } else { zig_unreachable(); @@ -6304,12 +6489,12 @@ static void do_code_gen(CodeGen *g) { for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { ZigVar *var = fn_table_entry->variable_list.at(var_i); - if (!type_has_bits(var->value->type)) { + if (!type_has_bits(var->var_type)) { continue; } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->value->type)) { + switch (type_requires_comptime(g, var->var_type)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: @@ -6319,11 +6504,11 @@ static void do_code_gen(CodeGen *g) { } if (var->src_arg_index == SIZE_MAX) { - var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); + 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), - var->value->type->di_type, !g->strip_debug_symbols, 0); + var->var_type->di_type, !g->strip_debug_symbols, 0); } else if (is_c_abi) { fn_walk_var.data.vars.var = var; @@ -6333,16 +6518,16 @@ static void do_code_gen(CodeGen *g) { ZigType *gen_type; FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; - if (handle_is_ptr(var->value->type)) { + if (handle_is_ptr(var->var_type)) { if (gen_info->is_byval) { - gen_type = var->value->type; + gen_type = var->var_type; } else { gen_type = gen_info->type; } var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index); } else { - gen_type = var->value->type; - var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); + gen_type = var->var_type; + var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); } if (var->decl_node) { var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), @@ -7458,9 +7643,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; this_val->special = ConstValSpecialStatic; this_val->type = struct_type; - this_val->data.x_struct.parent.id = ConstParentIdArray; - this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array; - this_val->data.x_struct.parent.data.p_array.elem_index = i; + this_val->parent.id = ConstParentIdArray; + this_val->parent.data.p_array.array_val = test_fn_array; + this_val->parent.data.p_array.elem_index = i; this_val->data.x_struct.fields = create_const_vals(2); ConstExprValue *name_field = &this_val->data.x_struct.fields[0]; diff --git a/src/ir.cpp b/src/ir.cpp index b184252a2e..06eb4a47f1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -167,6 +167,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *dest_type, IrInstruction *dest_type_src); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); +static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -178,15 +179,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c case ConstPtrSpecialRef: result = const_val->data.x_ptr.data.ref.pointee; break; - case ConstPtrSpecialBaseArray: - expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val); - result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[ - const_val->data.x_ptr.data.base_array.elem_index]; + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(g, array_val); + result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; break; + } case ConstPtrSpecialBaseStruct: result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ const_val->data.x_ptr.data.base_struct.field_index]; break; + case ConstPtrSpecialBaseErrorUnionCode: + result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set; + break; + case ConstPtrSpecialBaseErrorUnionPayload: + result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload; + break; + case ConstPtrSpecialBaseOptionalPayload: + result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional; + break; + case ConstPtrSpecialNull: + result = const_val; + break; case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialDiscard: @@ -198,6 +212,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c return result; } +static bool is_opt_err_set(ZigType *ty) { + return ty->id == ZigTypeIdErrorSet || + (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); +} + static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { if (a == b) return true; @@ -208,15 +227,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) return true; - return false; -} + if (is_opt_err_set(a) && is_opt_err_set(b)) + return true; -ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { - ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val); - if (const_val->type->id == ZigTypeIdPointer) { - assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type)); - } - return result; + return false; } static bool ir_should_inline(IrExecutable *exec, Scope *scope) { @@ -305,6 +319,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { return new_bb; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) { + return IrInstructionIdDeclVarSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) { + return IrInstructionIdDeclVarGen; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) { return IrInstructionIdCondBr; } @@ -337,10 +359,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { return IrInstructionIdBinOp; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { - return IrInstructionIdDeclVar; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { return IrInstructionIdExport; } @@ -449,8 +467,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { return IrInstructionIdTestNonNull; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) { - return IrInstructionIdUnwrapOptional; +static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) { + return IrInstructionIdOptionalUnwrapPtr; } static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { @@ -517,8 +535,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) { return IrInstructionIdEmbedFile; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) { - return IrInstructionIdCmpxchg; +static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) { + return IrInstructionIdCmpxchgSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) { + return IrInstructionIdCmpxchgGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { @@ -649,8 +671,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) return IrInstructionIdTestComptime; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) { - return IrInstructionIdPtrCast; +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) { + return IrInstructionIdPtrCastSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { + return IrInstructionIdPtrCastGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { @@ -915,7 +941,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so ir_ref_instruction(condition, irb->current_basic_block); ir_ref_bb(then_block); ir_ref_bb(else_block); - if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); + if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); return &cond_br_instruction->base; } @@ -931,16 +957,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou return &return_instruction->base; } -static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - assert(type_entry); - IrInstructionConst *const_instruction = ir_create_instruction(irb, scope, source_node); - const_instruction->base.value.type = type_entry; - const_instruction->base.value.special = ConstValSpecialStatic; - return &const_instruction->base; -} - static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_void; @@ -1188,14 +1204,11 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - if (fn_ref) - ir_ref_instruction(fn_ref, irb->current_basic_block); + if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); for (size_t i = 0; i < arg_count; i += 1) ir_ref_instruction(args[i], irb->current_basic_block); - if (async_allocator) - ir_ref_instruction(async_allocator, irb->current_basic_block); - if (new_stack != nullptr) - ir_ref_instruction(new_stack, irb->current_basic_block); + if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block); + if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); return &call_instruction->base; } @@ -1280,7 +1293,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, container_init_list_instruction->item_count = item_count; container_init_list_instruction->items = items; - ir_ref_instruction(container_type, irb->current_basic_block); + if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < item_count; i += 1) { ir_ref_instruction(items[i], irb->current_basic_block); } @@ -1355,10 +1368,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } -static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value) { - IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; @@ -1366,13 +1379,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s decl_var_instruction->align_value = align_value; decl_var_instruction->init_value = init_value; - if (var_type) ir_ref_instruction(var_type, irb->current_basic_block); - if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); + if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(init_value, irb->current_basic_block); return &decl_var_instruction->base; } +static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction, + ZigVar *var, IrInstruction *init_value) +{ + IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + decl_var_instruction->base.value.special = ConstValSpecialStatic; + decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void; + decl_var_instruction->var = var; + decl_var_instruction->init_value = init_value; + + ir_ref_instruction(init_value, ira->new_irb.current_basic_block); + + return &decl_var_instruction->base; +} + static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name, IrInstruction *target, IrInstruction *linkage) { @@ -1542,14 +1570,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod return &instruction->base; } -static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, - bool safety_check_on) +static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *base_ptr, bool safety_check_on) { - IrInstructionUnwrapOptional *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; instruction->safety_check_on = safety_check_on; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(base_ptr, irb->current_basic_block); return &instruction->base; } @@ -1765,13 +1793,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, - IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, +static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value, - bool is_weak, - ZigType *type, AtomicOrder success_order, AtomicOrder failure_order) + bool is_weak) { - IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; instruction->ptr = ptr; instruction->cmp_value = cmp_value; @@ -1779,16 +1806,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so instruction->success_order_value = success_order_value; instruction->failure_order_value = failure_order_value; instruction->is_weak = is_weak; - instruction->type = type; - instruction->success_order = success_order; - instruction->failure_order = failure_order; - if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(type_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(cmp_value, irb->current_basic_block); ir_ref_instruction(new_value, irb->current_basic_block); - if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block); - if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block); + ir_ref_instruction(success_order_value, irb->current_basic_block); + ir_ref_instruction(failure_order_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, + AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) +{ + IrInstructionCmpxchgGen *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->ptr = ptr; + instruction->cmp_value = cmp_value; + instruction->new_value = new_value; + instruction->success_order = success_order; + instruction->failure_order = failure_order; + instruction->is_weak = is_weak; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); + ir_ref_instruction(new_value, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2060,12 +2104,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) + IrInstruction *err_union) { IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + instruction->err_union = err_union; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(err_union, irb->current_basic_block); return &instruction->base; } @@ -2115,20 +2159,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } -static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *ptr) { - IrInstructionPtrCast *instruction = ir_build_instruction( + IrInstructionPtrCastSrc *instruction = ir_build_instruction( irb, scope, source_node); instruction->dest_type = dest_type; instruction->ptr = ptr; - if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); return &instruction->base; } +static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *ptr_type, IrInstruction *ptr) +{ + IrInstructionPtrCastGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ptr_type; + instruction->ptr = ptr; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *value) { @@ -2807,10 +2864,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o Scope *defer_expr_scope = defer_node->data.defer.expr_scope; IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); if (defer_expr_value != irb->codegen->invalid_instruction) { - if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) { + if (defer_expr_value->value.type != nullptr && + defer_expr_value->value.type->id == ZigTypeIdUnreachable) + { is_noreturn = true; } else { - ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value)); + ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, + defer_expr_value)); } } } @@ -3065,7 +3125,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s variable_entry->mem_slot_index = SIZE_MAX; variable_entry->is_comptime = is_comptime; variable_entry->src_arg_index = SIZE_MAX; - variable_entry->value = create_const_vals(1); + variable_entry->const_value = create_const_vals(1); if (is_comptime != nullptr) { is_comptime->ref_count += 1; @@ -3080,20 +3140,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s ErrorMsg *msg = add_node_error(codegen, node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } else { ZigType *type; if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { add_node_error(codegen, node, buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } else { Tld *tld = find_decl(codegen, parent_scope, name); if (tld != nullptr) { ErrorMsg *msg = add_node_error(codegen, node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } } } @@ -3156,7 +3216,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode scope_block->incoming_blocks = &incoming_blocks; scope_block->incoming_values = &incoming_values; scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); - scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope)); + scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, + ir_should_inline(irb->exec, parent_scope)); } bool is_continuation_unreachable = false; @@ -3174,9 +3235,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode // defer starts a new scope child_scope = statement_node->data.defer.child_scope; assert(child_scope); - } else if (statement_value->id == IrInstructionIdDeclVar) { + } else if (statement_value->id == IrInstructionIdDeclVarSrc) { // variable declarations start a new scope - IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; + IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value; child_scope = decl_var_instruction->var->child_scope; } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) { // this statement's value must be void @@ -3331,7 +3392,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); } -static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeBinOpExpr); AstNode *op1_node = node->data.bin_op_expr.op1; @@ -3365,7 +3426,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -3483,7 +3544,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) case BinOpTypeMergeErrorSets: return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); case BinOpTypeUnwrapOptional: - return ir_gen_maybe_ok_or(irb, scope, node); + return ir_gen_orelse(irb, scope, node); case BinOpTypeErrorUnion: return ir_gen_error_union(irb, scope, node); } @@ -3542,6 +3603,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, buf_ptr(variable_name))); return irb->codegen->invalid_instruction; } + assert(err == ErrorPrimitiveTypeNotFound); } else { IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); if (lval == LValPtr) { @@ -3904,9 +3966,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg5_value == irb->codegen->invalid_instruction) return arg5_value; - IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), - nullptr, AtomicOrderUnordered, AtomicOrderUnordered); + IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, + arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); return ir_lval_wrap(irb, scope, cmpxchg, lval); } case BuiltinFnIdFence: @@ -4346,7 +4407,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, ptr_cast, lval); } case BuiltinFnIdBitCast: @@ -4784,7 +4845,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node } } - IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr); + IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, + is_async, async_allocator, nullptr); return ir_lval_wrap(irb, scope, fn_call, lval); } @@ -4793,7 +4855,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); if (condition == irb->codegen->invalid_instruction) - return condition; + return irb->codegen->invalid_instruction; IrInstruction *is_comptime; if (ir_should_inline(irb->exec, scope)) { @@ -4816,7 +4878,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); if (then_expr_result == irb->codegen->invalid_instruction) - return then_expr_result; + return irb->codegen->invalid_instruction; IrBasicBlock *after_then_block = irb->current_basic_block; if (!instr_is_unreachable(then_expr_result)) ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); @@ -4826,7 +4888,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode if (else_node) { else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); if (else_expr_result == irb->codegen->invalid_instruction) - return else_expr_result; + return irb->codegen->invalid_instruction; } else { else_expr_result = ir_build_const_void(irb, scope, node); } @@ -4927,7 +4989,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode ptr_len, align_value, bit_offset_start, host_int_bytes); } -static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, +static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, LVal lval) { IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); @@ -5053,11 +5115,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); - // we detect IrInstructionIdDeclVar in gen_block to make sure the next node + // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node // is inside var->child_scope if (!is_extern && !variable_declaration->expr) { - var->value->type = irb->codegen->builtin_types.entry_invalid; + var->var_type = irb->codegen->builtin_types.entry_invalid; add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); return irb->codegen->invalid_instruction; } @@ -5084,7 +5146,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod if (init_value == irb->codegen->invalid_instruction) return init_value; - return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value); + return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value); } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5140,7 +5202,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n err_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); - ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); } ZigList incoming_values = {0}; @@ -5180,7 +5242,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5220,10 +5282,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n } ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); - ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5380,7 +5442,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo Scope *child_scope = elem_var->child_scope; IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -5398,7 +5460,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); + ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); @@ -5622,8 +5684,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile); } -static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeTestExpr); +static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeIfOptional); Buf *var_symbol = node->data.test_expr.var_symbol; AstNode *expr_node = node->data.test_expr.target_node; @@ -5661,9 +5723,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -5738,7 +5800,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -5763,7 +5825,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * err_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -5818,7 +5880,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } IrInstruction *var_type = nullptr; // infer the type - ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); } else { child_scope = scope; } @@ -6228,7 +6290,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); } -static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeUnwrapErrorExpr); AstNode *op1_node = node->data.unwrap_err_expr.op1; @@ -6242,7 +6304,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); return irb->codegen->invalid_instruction; } - return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone); + return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone); } @@ -6276,7 +6338,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val); } else { err_scope = parent_scope; } @@ -6312,7 +6374,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; if (need_comma) buf_append_char(name, ','); - render_const_value(codegen, name, var_scope->var->value); + // TODO: const ptr reinterpret here to make the var type agree with the value? + render_const_value(codegen, name, var_scope->var->const_value); return true; } @@ -6562,7 +6625,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6640,7 +6703,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6756,7 +6819,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7050,7 +7113,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); if (lval == LValPtr) return unwrapped_ptr; @@ -7074,8 +7137,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); case NodeTypeIfErrorExpr: return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); - case NodeTypeTestExpr: - return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); + case NodeTypeIfOptional: + return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); case NodeTypeCompTime: @@ -7093,7 +7156,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSliceExpr: return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); case NodeTypeContainerDecl: return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); case NodeTypeFnProto: @@ -7152,6 +7215,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_ref_bb(irb->current_basic_block); ZigFn *fn_entry = exec_fn_entry(irb->exec); + bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; IrInstruction *coro_id; IrInstruction *u8_ptr_type; @@ -7172,27 +7236,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); - ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); + ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, ImplicitAllocatorIdArg); irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); - ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); + ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); @@ -7208,7 +7272,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); @@ -7286,8 +7350,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); - IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); - IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, + IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); + IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr); IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, fn_entry->type_entry->data.fn.fn_type_id.return_type); @@ -7303,7 +7367,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // Before we destroy the coroutine frame, we need to load the target promise into // a register or local variable which does not get spilled into the frame, // otherwise llvm tries to access memory inside the destroyed frame. - IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, + IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, false); IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); @@ -7338,7 +7402,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); @@ -7435,7 +7499,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal return val; } -static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { +static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); @@ -7445,16 +7509,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) if (value->value.special == ConstValSpecialRuntime) { exec_add_error_node(codegen, exec, value->source_node, buf_sprintf("unable to evaluate constant expression")); - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } - return value; + return &value->value; } else if (ir_has_side_effects(instruction)) { exec_add_error_node(codegen, exec, instruction->source_node, buf_sprintf("unable to evaluate constant expression")); - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } } - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { @@ -8768,13 +8832,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT size_t errors_count = 0; ZigType *err_set_type = nullptr; if (prev_inst->value.type->id == ZigTypeIdErrorSet) { + if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) { + return ira->codegen->builtin_types.entry_invalid; + } if (type_is_global_error_set(prev_inst->value.type)) { err_set_type = ira->codegen->builtin_types.entry_global_error_set; } else { err_set_type = prev_inst->value.type; - if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } update_errors_helper(ira->codegen, &errors, &errors_count); for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { @@ -8933,6 +8997,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (prev_type->id == ZigTypeIdArray) { convert_to_const_slice = true; } + if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { + return ira->codegen->builtin_types.entry_invalid; + } if (type_is_global_error_set(cur_type)) { err_set_type = ira->codegen->builtin_types.entry_global_error_set; continue; @@ -8940,9 +9007,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { continue; } - if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } update_errors_helper(ira->codegen, &errors, &errors_count); @@ -9432,14 +9496,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ } return true; } + +static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, + old_instruction->scope, old_instruction->source_node); + IrInstruction *new_instruction = &const_instruction->base; + new_instruction->value.type = ty; + new_instruction->value.special = ConstValSpecialStatic; + return new_instruction; +} + static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type, CastOp cast_op, bool need_alloca) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && cast_op != CastOpResizeSlice) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type, &result->value, wanted_type)) { @@ -9476,9 +9549,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; result->value.data.x_ptr.data.base_array.array_val = pointee; @@ -9517,8 +9588,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc assert(is_slice(wanted_type)); bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = value->value.data.x_ptr.mut; @@ -9653,15 +9723,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction) return instruction; } -static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { - IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, - old_instruction->scope, old_instruction->source_node); - IrInstruction *new_instruction = &const_instruction->base; - new_instruction->value.type = ty; - new_instruction->value.special = ConstValSpecialStatic; - return new_instruction; -} - static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type); result->value.data.x_type = ty; @@ -9719,13 +9780,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un zig_unreachable(); } -IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, +ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec) { if (expected_type != nullptr && type_is_invalid(expected_type)) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; IrExecutable *ir_executable = allocate(1); ir_executable->source_node = source_node; @@ -9738,13 +9799,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node ir_gen(codegen, node, scope, ir_executable); if (ir_executable->invalid) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); ast_render(codegen, stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); - ir_print(codegen, stderr, ir_executable, 4); + ir_print(codegen, stderr, ir_executable, 2); fprintf(stderr, "}\n"); } IrExecutable *analyzed_executable = allocate(1); @@ -9760,11 +9821,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node analyzed_executable->begin_scope = scope; ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); if (type_is_invalid(result_type)) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; if (codegen->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); - ir_print(codegen, stderr, analyzed_executable, 4); + ir_print(codegen, stderr, analyzed_executable, 2); fprintf(stderr, "}\n"); } @@ -9838,7 +9899,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { return const_val->data.x_ptr.data.fn.fn_entry; } -static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { +static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *wanted_type) +{ assert(wanted_type->id == ZigTypeIdOptional); if (instr_is_comptime(value)) { @@ -9854,7 +9917,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.special = ConstValSpecialStatic; - if (get_codegen_ptr_type(wanted_type) != nullptr) { + if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) { copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); } else { const_instruction->base.value.data.x_optional = val; @@ -9885,11 +9948,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction if (!val) return ira->codegen->invalid_instruction; + ConstExprValue *err_set_val = create_const_vals(1); + err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->special = ConstValSpecialStatic; + err_set_val->data.x_err_set = nullptr; + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_err_union.err = nullptr; + const_instruction->base.value.data.x_err_union.error_set = err_set_val; const_instruction->base.value.data.x_err_union.payload = val; return &const_instruction->base; } @@ -9954,11 +10022,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so if (!val) return ira->codegen->invalid_instruction; + ConstExprValue *err_set_val = create_const_vals(1); + err_set_val->special = ConstValSpecialStatic; + err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->data.x_err_set = val->data.x_err_set; + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_err_union.err = val->data.x_err_set; + const_instruction->base.value.data.x_err_union.error_set = err_set_val; const_instruction->base.value.data.x_err_union.payload = nullptr; return &const_instruction->base; } @@ -9980,8 +10053,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.special = ConstValSpecialStatic; if (get_codegen_ptr_type(wanted_type) != nullptr) { - const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull; + } else if (is_opt_err_set(wanted_type)) { + const_instruction->base.value.data.x_err_set = nullptr; } else { const_instruction->base.value.data.x_optional = nullptr; } @@ -10014,7 +10088,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi source_instruction->source_node, value, is_const, is_volatile); new_instruction->value.type = ptr_type; new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; - if (type_has_bits(ptr_type)) { + if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); assert(fn_entry); fn_entry->alloca_list.append(new_instruction); @@ -10040,20 +10114,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s ZigType *array_type = array->value.type; assert(array_type->id == ZigTypeIdArray); - if (instr_is_comptime(array)) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + if (instr_is_comptime(array) || array_type->data.array.len == 0) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true); result->value.type = wanted_type; return result; } - IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, ira->codegen->builtin_types.entry_usize); + IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); init_const_usize(ira->codegen, &start->value, 0); - IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, ira->codegen->builtin_types.entry_usize); + IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); init_const_usize(ira->codegen, &end->value, array_type->data.array.len); if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); @@ -10092,8 +10163,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); return result; } @@ -10103,8 +10173,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour actual_type->data.enumeration.src_field_count == 1) { assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_bigint(&result->value, wanted_type, &actual_type->data.enumeration.fields[0].value); return result; @@ -10127,8 +10196,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag); @@ -10139,8 +10207,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && wanted_type->data.enumeration.src_field_count == 1) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field; @@ -10157,8 +10224,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *wanted_type) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_undefined(ira->codegen, &result->value); return result; } @@ -10190,8 +10256,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); @@ -10246,8 +10311,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; } } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.type = wanted_type; if (wanted_type->id == ZigTypeIdInt) { bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); @@ -10301,8 +10365,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); return result; } @@ -10320,8 +10383,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (wanted_type->id == ZigTypeIdComptimeFloat) { float_init_float(&result->value, val); } else if (wanted_type->id == ZigTypeIdComptimeInt) { @@ -10344,8 +10406,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) { return ira->codegen->invalid_instruction; @@ -10409,12 +10470,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); ErrorTableEntry *err; if (err_type->id == ZigTypeIdErrorUnion) { - err = val->data.x_err_union.err; + err = val->data.x_err_union.error_set->data.x_err_set; } else if (err_type->id == ZigTypeIdErrorSet) { err = val->data.x_err_set; } else { @@ -10449,15 +10509,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc return ira->codegen->invalid_instruction; } if (err_set_type->data.error_set.err_count == 0) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); bigint_init_unsigned(&result->value.data.x_bigint, 0); return result; } else if (err_set_type->data.error_set.err_count == 1) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; bigint_init_unsigned(&result->value.data.x_bigint, err->value); return result; @@ -10504,8 +10560,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou array_val->type = array_type; array_val->data.x_array.special = ConstArraySpecialNone; array_val->data.x_array.data.s_none.elements = pointee; - array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar; - array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee; + array_val->parent.id = ConstParentIdScalar; + array_val->parent.data.p_scalar.scalar_val = pointee; IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -10653,12 +10709,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; } @@ -10682,7 +10738,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type); } } } @@ -10735,6 +10791,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) { + if (value->value.special == ConstValSpecialUndef) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + result->value.special = ConstValSpecialUndef; + return result; + } if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { IrInstruction *result = ir_const(ira, source_instr, wanted_type); @@ -10788,6 +10849,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // cast from [N]T to []const T + // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == ZigTypeIdPointer); @@ -10800,6 +10862,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // cast from [N]T to ?[]const T + // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this if (wanted_type->id == ZigTypeIdOptional && is_slice(wanted_type->data.maybe.child_type) && actual_type->id == ZigTypeIdArray) @@ -10894,7 +10957,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // cast from error set to error union type + // cast from E to E!T if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorSet) { @@ -11046,8 +11109,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ZigType *child_type = type_entry->data.pointer.child_type; // dereferencing a *u0 is comptime known to be 0 if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, child_type); + IrInstruction *result = ir_const(ira, source_instruction, child_type); init_const_unsigned_negative(&result->value, child_type, 0, false); return result; } @@ -11061,8 +11123,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc { ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, child_type); + IrInstruction *result = ir_const(ira, source_instruction, child_type); if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, &ptr->value))) @@ -11074,7 +11135,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc } } } - // TODO if the instruction is a const ref instruction we can skip it + // if the instruction is a const ref instruction we can skip it + if (ptr->id == IrInstructionIdRef) { + IrInstructionRef *ref_inst = reinterpret_cast(ptr); + return ref_inst->value; + } IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); load_ptr_instruction->value.type = child_type; @@ -11321,8 +11386,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) { IrInstruction *result = ir_const(ira, &instruction->base, nullptr); - // TODO determine if we need to use copy_const_val here - result->value = instruction->base.value; + copy_const_val(&result->value, &instruction->base.value, true); return result; } @@ -11397,6 +11461,8 @@ static bool optional_value_is_null(ConstExprValue *val) { if (get_codegen_ptr_type(val->type) != nullptr) { return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else if (is_opt_err_set(val->type)) { + return val->data.x_err_set == nullptr; } else { return val->data.x_optional == nullptr; } @@ -11596,19 +11662,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; - bool requires_comptime; - switch (type_requires_comptime(ira->codegen, resolved_type)) { - case ReqCompTimeYes: - requires_comptime = true; - break; - case ReqCompTimeNo: - requires_comptime = false; - break; - case ReqCompTimeInvalid: + bool one_possible_value; + switch (type_has_one_possible_value(ira->codegen, resolved_type)) { + case OnePossibleValueInvalid: return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + one_possible_value = true; + break; + case OnePossibleValueNo: + one_possible_value = false; + break; } - bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type); if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); if (op1_val == nullptr) @@ -12497,13 +12562,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { +static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, + IrInstructionDeclVarSrc *decl_var_instruction) +{ Error err; ZigVar *var = decl_var_instruction->var; IrInstruction *init_value = decl_var_instruction->init_value->child; if (type_is_invalid(init_value->value.type)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -12514,7 +12581,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct ZigType *proposed_type = ir_resolve_type(ira, var_type); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } } @@ -12539,7 +12606,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct case ReqCompTimeInvalid: result_type = ira->codegen->builtin_types.entry_invalid; break; - case ReqCompTimeYes: { + case ReqCompTimeYes: var_class_requires_const = true; if (!var->gen_is_const && !is_comptime_var) { ir_add_error_node(ira, source_node, @@ -12548,7 +12615,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct result_type = ira->codegen->builtin_types.entry_invalid; } break; - } case ReqCompTimeNo: if (casted_init_value->value.special == ConstValSpecialStatic && casted_init_value->value.type->id == ZigTypeIdFn && @@ -12567,7 +12633,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct break; } - if (var->value->type != nullptr && !is_comptime_var) { + if (var->var_type != nullptr && !is_comptime_var) { // This is at least the second time we've seen this variable declaration during analysis. // This means that this is actually a different variable due to, e.g. an inline while loop. // We make a new variable so that it can hold a different type, and so the debug info can @@ -12589,8 +12655,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct // This must be done after possibly creating a new variable above var->ref_count = 0; - var->value->type = result_type; - assert(var->value->type); + var->var_type = result_type; + assert(var->var_type); if (type_is_invalid(result_type)) { return ir_const_void(ira, &decl_var_instruction->base); @@ -12598,13 +12664,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct if (decl_var_instruction->align_value == nullptr) { if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ir_const_void(ira, &decl_var_instruction->base); } var->align_bytes = get_abi_alignment(ira->codegen, result_type); } else { if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; } } @@ -12621,7 +12687,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct } else if (is_comptime_var) { ir_add_error(ira, &decl_var_instruction->base, buf_sprintf("cannot store runtime value in compile time variable")); - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -12629,11 +12695,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct if (fn_entry) fn_entry->variable_list.append(var); - IrInstruction *result = ir_build_var_decl(&ira->new_irb, - decl_var_instruction->base.scope, decl_var_instruction->base.source_node, - var, var_type, nullptr, casted_init_value); - result->value.type = ira->codegen->builtin_types.entry_void; - return result; + return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); } static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { @@ -12963,7 +13025,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node Buf *param_name = param_decl_node->data.param_decl.name; ZigVar *var = add_variable(ira->codegen, param_decl_node, - *exec_scope, param_name, true, arg_val, nullptr); + *exec_scope, param_name, true, arg_val, nullptr, arg_val->type); *exec_scope = var->child_scope; *next_proto_i += 1; @@ -13021,7 +13083,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod if (!param_name) return false; if (!is_var_args) { ZigVar *var = add_variable(ira->codegen, param_decl_node, - *child_scope, param_name, true, arg_val, nullptr); + *child_scope, param_name, true, arg_val, nullptr, arg_val->type); *child_scope = var->child_scope; var->shadowable = !comptime_arg; @@ -13075,9 +13137,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { return fn_entry->variable_list.at(next_var_i); } -static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, - ZigVar *var) -{ +static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { while (var->next_var != nullptr) { var = var->next_var; } @@ -13086,14 +13146,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(ira->codegen->errors.length != 0); return ira->codegen->invalid_instruction; } - if (var->value->type == nullptr || type_is_invalid(var->value->type)) + if (var->var_type == nullptr || type_is_invalid(var->var_type)) return ira->codegen->invalid_instruction; bool comptime_var_mem = ir_get_var_is_comptime(var); ConstExprValue *mem_slot = nullptr; - if (var->value->special == ConstValSpecialStatic) { - mem_slot = var->value; + if (var->const_value->special == ConstValSpecialStatic) { + mem_slot = var->const_value; } else { if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { // find the relevant exec_context @@ -13122,7 +13182,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(!comptime_var_mem); ptr_mut = ConstPtrMutRuntimeVar; } - return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, + return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, ptr_mut, is_const, is_volatile, var->align_bytes); } } @@ -13133,7 +13193,7 @@ no_mem_slot: IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, instruction->scope, instruction->source_node, var); - var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, + var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); @@ -13142,6 +13202,96 @@ no_mem_slot: return var_ptr_instruction; } +static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *ptr, IrInstruction *uncasted_value) +{ + if (ptr->value.type->id != ZigTypeIdPointer) { + ir_add_error(ira, ptr, + buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); + return ira->codegen->invalid_instruction; + } + + if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { + return ir_const_void(ira, source_instr); + } + + if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) { + ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); + return ira->codegen->invalid_instruction; + } + + ZigType *child_type = ptr->value.type->data.pointer.child_type; + IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type); + if (value == ira->codegen->invalid_instruction) + return ira->codegen->invalid_instruction; + + if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { + ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); + return ira->codegen->invalid_instruction; + } + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { + if (instr_is_comptime(value)) { + ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node); + if (dest_val == nullptr) + return ira->codegen->invalid_instruction; + if (dest_val->special != ConstValSpecialRuntime) { + // TODO this allows a value stored to have the original value modified and then + // have that affect what should be a copy. We need some kind of advanced copy-on-write + // system to make these two tests pass at the same time: + // * "string literal used as comptime slice is memoized" + // * "comptime modification of const struct field" - except modified to avoid + // ConstPtrMutComptimeVar, thus defeating the logic below. + bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; + copy_const_val(dest_val, &value->value, same_global_refs); + if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; + break; + case OnePossibleValueYes: + break; + } + } + return ir_const_void(ira, source_instr); + } + } + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in compile time variable")); + ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + dest_val->type = ira->codegen->builtin_types.entry_invalid; + + return ira->codegen->invalid_instruction; + } + } + + switch (type_requires_comptime(ira->codegen, child_type)) { + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeYes: + switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const_void(ira, source_instr); + } + zig_unreachable(); + case ReqCompTimeNo: + break; + } + + IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, + ptr, value); + result->value.type = ira->codegen->builtin_types.entry_void; + return result; +} + static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) @@ -13286,7 +13436,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call } bool cacheable = fn_eval_cacheable(exec_scope, return_type); - IrInstruction *result = nullptr; + ConstExprValue *result = nullptr; if (cacheable) { auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); if (entry) @@ -13302,18 +13452,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; - if (result->value.type->id == ZigTypeIdErrorUnion) { - if (result->value.data.x_err_union.err != nullptr) { + if (result->type->id == ZigTypeIdErrorUnion) { + ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; + if (err != nullptr) { inferred_err_set_type->data.error_set.err_count = 1; inferred_err_set_type->data.error_set.errors = allocate(1); - inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err; + inferred_err_set_type->data.error_set.errors[0] = err; } - ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type; + ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type; inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; - } else if (result->value.type->id == ZigTypeIdErrorSet) { - inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors; + } else if (result->type->id == ZigTypeIdErrorSet) { + inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; + inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors; } } @@ -13321,13 +13472,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ira->codegen->memoized_fn_eval_table.put(exec_scope, result); } - if (type_is_invalid(result->value.type)) + if (type_is_invalid(result->type)) return ira->codegen->invalid_instruction; } - IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type); - // TODO should we use copy_const_val? - new_instruction->value = result->value; + IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); + copy_const_val(&new_instruction->value, result, true); new_instruction->value.type = return_type; return ir_finish_anal(ira, new_instruction); } @@ -13486,18 +13636,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, first_var_arg, inst_fn_type_id.param_count); ZigVar *var = add_variable(ira->codegen, param_decl_node, - impl_fn->child_scope, param_name, true, var_args_val, nullptr); + impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type); impl_fn->child_scope = var->child_scope; } if (fn_proto_node->data.fn_proto.align_expr != nullptr) { - IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, + ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, + impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); + const_instruction->base.value = *align_result; uint32_t align_bytes = 0; - ir_resolve_align(ira, align_result, &align_bytes); + ir_resolve_align(ira, &const_instruction->base, &align_bytes); impl_fn->align_bytes = align_bytes; inst_fn_type_id.alignment = align_bytes; } @@ -13575,12 +13728,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ira->codegen->fn_defs.append(impl_fn); } - ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; - if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) { + FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; + if (fn_type_can_fail(impl_fn_type_id)) { parent_fn_entry->calls_or_awaits_errorable_fn = true; } - size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; + size_t impl_param_count = impl_fn_type_id->param_count; if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); @@ -13593,9 +13746,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call call_instruction->base.scope, call_instruction->base.source_node, impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, call_instruction->is_async, nullptr, casted_new_stack); - new_call_instruction->value.type = return_type; + new_call_instruction->value.type = impl_fn_type_id->return_type; - ir_add_alloca(ira, new_call_instruction, return_type); + ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -13790,6 +13943,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source switch (ptr_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); + case ConstPtrSpecialNull: + if (dst_size == 0) + return ErrorNone; + opt_ir_add_error_node(ira, codegen, source_node, + buf_sprintf("attempt to read %zu bytes from null pointer", + dst_size)); + return ErrorSemanticAnalyzeFail; case ConstPtrSpecialRef: { opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", @@ -13822,6 +13982,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source return ErrorNone; } case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialBaseErrorUnionCode: + case ConstPtrSpecialBaseErrorUnionPayload: + case ConstPtrSpecialBaseOptionalPayload: case ConstPtrSpecialDiscard: case ConstPtrSpecialHardCodedAddr: case ConstPtrSpecialFunction: @@ -14017,9 +14180,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) return ir_unreach_error(ira); - if (is_comptime || instr_is_comptime(condition)) { + ZigType *bool_type = ira->codegen->builtin_types.entry_bool; + IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); + if (type_is_invalid(casted_condition->value.type)) + return ir_unreach_error(ira); + + if (is_comptime || instr_is_comptime(casted_condition)) { bool cond_is_true; - if (!ir_resolve_bool(ira, condition, &cond_is_true)) + if (!ir_resolve_bool(ira, casted_condition, &cond_is_true)) return ir_unreach_error(ira); IrBasicBlock *old_dest_block = cond_is_true ? @@ -14038,11 +14206,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi return ir_finish_anal(ira, result); } - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); - if (casted_condition == ira->codegen->invalid_instruction) - return ir_unreach_error(ira); - assert(cond_br_instruction->then_block != cond_br_instruction->else_block); IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); if (new_then_block == nullptr) @@ -14081,8 +14244,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh if (value->value.special != ConstValSpecialRuntime) { IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr); - // TODO use copy_const_val? - result->value = value->value; + copy_const_val(&result->value, &value->value, true); return result; } else { return value; @@ -14131,14 +14293,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh if (type_is_invalid(resolved_type)) return ira->codegen->invalid_instruction; - if (resolved_type->id == ZigTypeIdComptimeFloat || - resolved_type->id == ZigTypeIdComptimeInt || - resolved_type->id == ZigTypeIdNull || - resolved_type->id == ZigTypeIdUndefined) - { - ir_add_error_node(ira, phi_instruction->base.source_node, - buf_sprintf("unable to infer expression type")); + switch (type_has_one_possible_value(ira->codegen, resolved_type)) { + case OnePossibleValueInvalid: return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const(ira, &phi_instruction->base, resolved_type); + case OnePossibleValueNo: + break; + } + + switch (type_requires_comptime(ira->codegen, resolved_type)) { + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeYes: + ir_add_error_node(ira, phi_instruction->base.source_node, + buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name))); + return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + break; } bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); @@ -14428,10 +14600,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } case ConstPtrSpecialBaseStruct: zig_panic("TODO elem ptr on a const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO elem ptr on a const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO elem ptr on a const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO elem ptr on a const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO element ptr of a function casted to a ptr"); + case ConstPtrSpecialNull: + zig_panic("TODO elem ptr on a null pointer"); } if (new_index >= mem_size) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, @@ -14481,10 +14661,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } case ConstPtrSpecialBaseStruct: zig_panic("TODO elem ptr on a slice backed by const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO elem ptr on a slice backed by const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO elem ptr on a slice backed by const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO elem ptr on a slice backed by const optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); + case ConstPtrSpecialNull: + zig_panic("TODO elem ptr on a slice has a null pointer"); } return result; } else if (array_type->id == ZigTypeIdArray) { @@ -15171,74 +15359,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc } } -static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { - IrInstruction *ptr = load_ptr_instruction->ptr->child; - if (type_is_invalid(ptr->value.type)) - return ira->codegen->invalid_instruction; - return ir_get_deref(ira, &load_ptr_instruction->base, ptr); -} - -static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { - IrInstruction *ptr = store_ptr_instruction->ptr->child; +static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) { + IrInstruction *ptr = instruction->ptr->child; if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *value = store_ptr_instruction->value->child; + IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - if (ptr->value.type->id != ZigTypeIdPointer) { - ir_add_error(ira, ptr, - buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); + return ir_analyze_store_ptr(ira, &instruction->base, ptr, value); +} + +static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) { + IrInstruction *ptr = instruction->ptr->child; + if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - } - - if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { - return ir_const_void(ira, &store_ptr_instruction->base); - } - - if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) { - ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_instruction; - } - - ZigType *child_type = ptr->value.type->data.pointer.child_type; - IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type); - if (casted_value == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; - - if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { - ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_instruction; - } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { - if (instr_is_comptime(casted_value)) { - ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node); - if (dest_val == nullptr) - return ira->codegen->invalid_instruction; - if (dest_val->special != ConstValSpecialRuntime) { - *dest_val = casted_value->value; - if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { - ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base; - } - return ir_const_void(ira, &store_ptr_instruction->base); - } - } - ir_add_error(ira, &store_ptr_instruction->base, - buf_sprintf("cannot store runtime value in compile time variable")); - ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; - - return ira->codegen->invalid_instruction; - } - } - - IrInstruction *result = ir_build_store_ptr(&ira->new_irb, - store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node, - ptr, casted_value); - result->value.type = ira->codegen->builtin_types.entry_void; - return result; + return ir_get_deref(ira, &instruction->base, ptr); } static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { @@ -15709,11 +15846,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) - return ira->codegen->invalid_instruction; - +static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { ZigType *type_entry = value->value.type; if (type_entry->id == ZigTypeIdOptional) { @@ -15722,60 +15855,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns if (!maybe_val) return ira->codegen->invalid_instruction; - return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val)); + return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val)); } IrInstruction *result = ir_build_test_nonnull(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); + source_inst->scope, source_inst->source_node, value); result->value.type = ira->codegen->builtin_types.entry_bool; return result; } else if (type_entry->id == ZigTypeIdNull) { - return ir_const_bool(ira, &instruction->base, false); + return ir_const_bool(ira, source_inst, false); } else { - return ir_const_bool(ira, &instruction->base, true); + return ir_const_bool(ira, source_inst, true); } } -static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, - IrInstructionUnwrapOptional *unwrap_maybe_instruction) -{ - IrInstruction *value = unwrap_maybe_instruction->value->child; +static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { + IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + return ir_analyze_test_non_null(ira, &instruction->base, value); +} + +static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on) +{ + ZigType *ptr_type = base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id != ZigTypeIdOptional) { - ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node, + + if (type_entry->id != ZigTypeIdOptional) { + ir_add_error_node(ira, base_ptr->source_node, buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + ZigType *child_type = type_entry->data.maybe.child_type; ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0); - if (instr_is_comptime(value)) { - ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); + if (instr_is_comptime(base_ptr)) { + ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); if (!val) return ira->codegen->invalid_instruction; - ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node); + ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); if (maybe_val == nullptr) return ira->codegen->invalid_instruction; if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { if (optional_value_is_null(maybe_val)) { - ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); + ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type); + IrInstruction *result = ir_const(ira, source_instr, result_type); ConstExprValue *out_val = &result->value; out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.mut = val->data.x_ptr.mut; - if (type_is_codegen_pointer(child_type)) { + if (types_have_same_zig_comptime_repr(type_entry, child_type)) { out_val->data.x_ptr.data.ref.pointee = maybe_val; } else { out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; @@ -15784,13 +15923,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, } } - IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb, - unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node, - value, unwrap_maybe_instruction->safety_check_on); + IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr, safety_check_on); result->value.type = result_type; return result; } +static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, + IrInstructionOptionalUnwrapPtr *instruction) +{ + IrInstruction *base_ptr = instruction->base_ptr->child; + if (type_is_invalid(base_ptr->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); +} + static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) { IrInstruction *value = ctz_instruction->value->child; if (type_is_invalid(value->value.type)) { @@ -16091,9 +16239,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *result = ir_build_load_ptr(&ira->new_irb, - switch_target_instruction->base.scope, switch_target_instruction->base.source_node, - target_value_ptr); + IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); result->value.type = target_type; return result; } @@ -16123,8 +16269,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); union_value->value.type = target_type; IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, @@ -16148,8 +16293,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); enum_value->value.type = target_type; return enum_value; } @@ -16306,7 +16450,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI Error err; assert(container_type->id == ZigTypeIdUnion); - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; if (instr_field_count != 1) { @@ -16350,12 +16494,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI ConstExprValue *out_val = &result->value; out_val->data.x_union.payload = field_val; out_val->data.x_union.tag = type_field->enum_field->value; - - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdUnion; - parent->data.p_union.union_val = out_val; - } + out_val->parent.id = ConstParentIdUnion; + out_val->parent.data.p_union.union_val = out_val; return result; } @@ -16382,7 +16522,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; size_t actual_field_count = container_type->data.structure.src_field_count; @@ -16461,9 +16601,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc if (const_val.special == ConstValSpecialStatic) { IrInstruction *result = ir_const(ira, instruction, nullptr); ConstExprValue *out_val = &result->value; - // TODO copy_const_val? - *out_val = const_val; - result->value.type = container_type; + copy_const_val(out_val, &const_val, true); + out_val->type = container_type; for (size_t i = 0; i < instr_field_count; i += 1) { ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; @@ -16495,127 +16634,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { - IrInstruction *container_type_value = instruction->container_type->child; - if (type_is_invalid(container_type_value->value.type)) + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; size_t elem_count = instruction->item_count; - if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; - if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, - 0, nullptr); - } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { - // array is same as slice init but we make a compile error if the length is wrong - ZigType *child_type; - if (container_type->id == ZigTypeIdArray) { - child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); + if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, + 0, nullptr); + } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { + // array is same as slice init but we make a compile error if the length is wrong + ZigType *child_type; + if (container_type->id == ZigTypeIdArray) { + child_type = container_type->data.array.child_type; + if (container_type->data.array.len != elem_count) { + ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); - ir_add_error(ira, &instruction->base, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_instruction; - } - } else { - ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; - assert(pointer_type->id == ZigTypeIdPointer); - child_type = pointer_type->data.pointer.child_type; + ir_add_error(ira, &instruction->base, + buf_sprintf("expected %s literal, found %s literal", + buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); + return ira->codegen->invalid_instruction; } + } else { + ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; + assert(pointer_type->id == ZigTypeIdPointer); + child_type = pointer_type->data.pointer.child_type; + } - ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); + ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.type = fixed_size_array_type; - const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); + ConstExprValue const_val = {}; + const_val.special = ConstValSpecialStatic; + const_val.type = fixed_size_array_type; + const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); - IrInstruction **new_items = allocate(elem_count); + IrInstruction **new_items = allocate(elem_count); - IrInstruction *first_non_const_instruction = nullptr; + IrInstruction *first_non_const_instruction = nullptr; - for (size_t i = 0; i < elem_count; i += 1) { - IrInstruction *arg_value = instruction->items[i]->child; - if (type_is_invalid(arg_value->value.type)) - return ira->codegen->invalid_instruction; + for (size_t i = 0; i < elem_count; i += 1) { + IrInstruction *arg_value = instruction->items[i]->child; + if (type_is_invalid(arg_value->value.type)) + return ira->codegen->invalid_instruction; - IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); - if (casted_arg == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; + IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); + if (casted_arg == ira->codegen->invalid_instruction) + return ira->codegen->invalid_instruction; - new_items[i] = casted_arg; - - if (const_val.special == ConstValSpecialStatic) { - if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { - ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); - if (!elem_val) - return ira->codegen->invalid_instruction; - - copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); - } else { - first_non_const_instruction = casted_arg; - const_val.special = ConstValSpecialRuntime; - } - } - } + new_items[i] = casted_arg; if (const_val.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, nullptr); - ConstExprValue *out_val = &result->value; - // TODO copy_const_val? - *out_val = const_val; - result->value.type = fixed_size_array_type; - for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; - ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = out_val; - parent->data.p_array.elem_index = i; - } + if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { + ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); + if (!elem_val) + return ira->codegen->invalid_instruction; + + copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); + } else { + first_non_const_instruction = casted_arg; + const_val.special = ConstValSpecialRuntime; } - return result; } + } - if (is_comptime) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_instruction; + if (const_val.special == ConstValSpecialStatic) { + IrInstruction *result = ir_const(ira, &instruction->base, nullptr); + ConstExprValue *out_val = &result->value; + copy_const_val(out_val, &const_val, true); + result->value.type = fixed_size_array_type; + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; + ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); + if (parent != nullptr) { + parent->id = ConstParentIdArray; + parent->data.p_array.array_val = out_val; + parent->data.p_array.elem_index = i; + } } + return result; + } - IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, - container_type_value, elem_count, new_items); - new_instruction->value.type = fixed_size_array_type; - ir_add_alloca(ira, new_instruction, fixed_size_array_type); - return new_instruction; - } else if (container_type->id == ZigTypeIdVoid) { - if (elem_count != 0) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); - return ira->codegen->invalid_instruction; - } - return ir_const_void(ira, &instruction->base); - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); + if (is_comptime) { + ir_add_error_node(ira, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); return ira->codegen->invalid_instruction; } + + IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, + nullptr, elem_count, new_items); + new_instruction->value.type = fixed_size_array_type; + ir_add_alloca(ira, new_instruction, fixed_size_array_type); + return new_instruction; + } else if (container_type->id == ZigTypeIdVoid) { + if (elem_count != 0) { + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("void expression expects no arguments")); + return ira->codegen->invalid_instruction; + } + return ir_const_void(ira, &instruction->base); } else { - ir_add_error(ira, container_type_value, - buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name))); + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("type '%s' does not support array initialization", + buf_ptr(&container_type->name))); return ira->codegen->invalid_instruction; } } -static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { +static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, + IrInstructionContainerInitFields *instruction) +{ IrInstruction *container_type_value = instruction->container_type->child; ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) @@ -16675,7 +16806,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type); + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set); if (type_is_invalid(casted_value->value.type)) return ira->codegen->invalid_instruction; @@ -16936,10 +17067,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig ZigVar *var = tld->var; - if ((err = ensure_complete_type(ira->codegen, var->value->type))) + if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) return ira->codegen->builtin_types.entry_invalid; - assert(var->value->type->id == ZigTypeIdMetaType); - return var->value->data.x_type; + + assert(var->const_value->type->id == ZigTypeIdMetaType); + return var->const_value->data.x_type; } static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) { @@ -16994,7 +17126,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco definition_array->special = ConstValSpecialStatic; definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); definition_array->data.x_array.special = ConstArraySpecialNone; - definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); @@ -17025,33 +17156,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; inner_fields[2].special = ConstValSpecialStatic; inner_fields[2].type = type_info_definition_data_type; - inner_fields[2].data.x_union.parent.id = ConstParentIdStruct; - inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; - inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; + inner_fields[2].parent.id = ConstParentIdStruct; + inner_fields[2].parent.data.p_struct.struct_val = definition_val; + inner_fields[2].parent.data.p_struct.field_index = 1; switch (curr_entry->value->id) { case TldIdVar: { ZigVar *var = ((TldVar *)curr_entry->value)->var; - if ((err = ensure_complete_type(ira->codegen, var->value->type))) + if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) return ErrorSemanticAnalyzeFail; - if (var->value->type->id == ZigTypeIdMetaType) - { + if (var->const_value->type->id == ZigTypeIdMetaType) { // We have a variable of type 'type', so it's actually a type definition. // 0: Data.Type: type bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); - inner_fields[2].data.x_union.payload = var->value; - } - else - { + inner_fields[2].data.x_union.payload = var->const_value; + } else { // We have a variable of another type, so we store the type of the variable. // 1: Data.Var: type bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); ConstExprValue *payload = create_const_vals(1); payload->type = ira->codegen->builtin_types.entry_type; - payload->data.x_type = var->value->type; + payload->data.x_type = var->const_value->type; inner_fields[2].data.x_union.payload = payload; } @@ -17071,8 +17199,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ConstExprValue *fn_def_val = create_const_vals(1); fn_def_val->special = ConstValSpecialStatic; fn_def_val->type = type_info_fn_def_type; - fn_def_val->data.x_struct.parent.id = ConstParentIdUnion; - fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2]; + fn_def_val->parent.id = ConstParentIdUnion; + fn_def_val->parent.data.p_union.union_val = &inner_fields[2]; ConstExprValue *fn_def_fields = create_const_vals(9); fn_def_val->data.x_struct.fields = fn_def_fields; @@ -17136,20 +17264,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco fn_arg_name_array->type = get_array_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr), fn_arg_count); fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); - for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) - { + for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true); - fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray; - fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array; - fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; + fn_arg_name_val->parent.id = ConstParentIdArray; + fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array; + fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index; } inner_fields[2].data.x_union.payload = fn_def_val; @@ -17442,7 +17568,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE enum_field_array->special = ConstValSpecialStatic; enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); enum_field_array->data.x_array.special = ConstArraySpecialNone; - enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false); @@ -17452,9 +17577,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); - enum_field_val->data.x_struct.parent.id = ConstParentIdArray; - enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array; - enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index; + enum_field_val->parent.id = ConstParentIdArray; + enum_field_val->parent.data.p_array.array_val = enum_field_array; + enum_field_val->parent.data.p_array.elem_index = enum_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); @@ -17481,7 +17606,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE error_array->special = ConstValSpecialStatic; error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); error_array->data.x_array.special = ConstArraySpecialNone; - error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); @@ -17505,9 +17629,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); error_val->data.x_struct.fields = inner_fields; - error_val->data.x_struct.parent.id = ConstParentIdArray; - error_val->data.x_struct.parent.data.p_array.array_val = error_array; - error_val->data.x_struct.parent.data.p_array.elem_index = error_index; + error_val->parent.id = ConstParentIdArray; + error_val->parent.data.p_array.array_val = error_array; + error_val->parent.data.p_array.elem_index = error_index; } break; @@ -17576,7 +17700,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE union_field_array->special = ConstValSpecialStatic; union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); union_field_array->data.x_array.special = ConstArraySpecialNone; - union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); @@ -17609,9 +17732,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); union_field_val->data.x_struct.fields = inner_fields; - union_field_val->data.x_struct.parent.id = ConstParentIdArray; - union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array; - union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index; + union_field_val->parent.id = ConstParentIdArray; + union_field_val->parent.data.p_array.array_val = union_field_array; + union_field_val->parent.data.p_array.elem_index = union_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); @@ -17651,7 +17774,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE struct_field_array->special = ConstValSpecialStatic; struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); struct_field_array->data.x_array.special = ConstArraySpecialNone; - struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); @@ -17685,9 +17807,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); struct_field_val->data.x_struct.fields = inner_fields; - struct_field_val->data.x_struct.parent.id = ConstParentIdArray; - struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array; - struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index; + struct_field_val->parent.id = ConstParentIdArray; + struct_field_val->parent.data.p_array.array_val = struct_field_array; + struct_field_val->parent.data.p_array.elem_index = struct_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 2); @@ -17757,7 +17879,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE fn_arg_array->special = ConstValSpecialStatic; fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); fn_arg_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false); @@ -17794,9 +17915,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE } fn_arg_val->data.x_struct.fields = inner_fields; - fn_arg_val->data.x_struct.parent.id = ConstParentIdArray; - fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array; - fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; + fn_arg_val->parent.id = ConstParentIdArray; + fn_arg_val->parent.data.p_array.array_val = fn_arg_array; + fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; } break; @@ -17840,8 +17961,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, if (payload != nullptr) { assert(payload->type->id == ZigTypeIdStruct); - payload->data.x_struct.parent.id = ConstParentIdUnion; - payload->data.x_struct.parent.data.p_union.union_val = out_val; + payload->parent.id = ConstParentIdUnion; + payload->parent.data.p_union.union_val = out_val; } return result; @@ -17913,10 +18034,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct // Execute the C import block like an inline function ZigType *void_type = ira->codegen->builtin_types.entry_void; - IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, + ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, &cimport_scope->buf, block_node, nullptr, nullptr); - if (type_is_invalid(cimport_result->value.type)) + if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; find_libc_include_path(ira->codegen); @@ -18066,7 +18187,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru return result; } -static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { +static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) { ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); if (type_is_invalid(operand_type)) return ira->codegen->invalid_instruction; @@ -18138,9 +18259,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi zig_panic("TODO compile-time execution of cmpxchg"); } - IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node, - nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak, - operand_type, success_order, failure_order); + IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, + casted_ptr, casted_cmp_value, casted_new_value, + success_order, failure_order, instruction->is_weak); result->value.type = get_optional_type(ira->codegen, operand_type); ir_add_alloca(ira, result, result->value.type); return result; @@ -18312,18 +18433,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type); } -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { - Error err; - - if (ty->id == ZigTypeIdPointer) { - if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } - - *result_align = get_ptr_align(ira->codegen, ty); - return ErrorNone; -} - static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; @@ -18442,6 +18551,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); } +static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { + Error err; + + ZigType *ptr_type = get_src_ptr_type(ty); + assert(ptr_type != nullptr); + if (ptr_type->id == ZigTypeIdPointer) { + if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return err; + } + + *result_align = get_ptr_align(ira->codegen, ty); + return ErrorNone; +} + static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) @@ -18646,10 +18769,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memset on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memset on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memset on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memset on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memset on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memset on null ptr"); } size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); @@ -18761,10 +18892,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); } if (dest_start + count > dest_end) { @@ -18797,10 +18936,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); } if (src_start + count > src_end) { @@ -18828,9 +18975,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction if (type_is_invalid(ptr_ptr->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = ptr_ptr->value.type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = ptr_type->data.pointer.child_type; + ZigType *ptr_ptr_type = ptr_ptr->value.type; + assert(ptr_ptr_type->id == ZigTypeIdPointer); + ZigType *array_type = ptr_ptr_type->data.pointer.child_type; IrInstruction *start = instruction->start->child; if (type_is_invalid(start->value.type)) @@ -18859,10 +19006,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, - ptr_type->data.pointer.is_const || is_comptime_const, - ptr_type->data.pointer.is_volatile, + ptr_ptr_type->data.pointer.is_const || is_comptime_const, + ptr_ptr_type->data.pointer.is_volatile, PtrLenUnknown, - ptr_type->data.pointer.explicit_alignment, 0, 0); + ptr_ptr_type->data.pointer.explicit_alignment, 0, 0); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else if (array_type->id == ZigTypeIdPointer) { if (array_type->data.pointer.ptr_len == PtrLenSingle) { @@ -18960,6 +19107,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialBaseStruct: zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO slice const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO slice const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO slice const inner optional payload"); case ConstPtrSpecialHardCodedAddr: array_val = nullptr; abs_offset = 0; @@ -18967,6 +19120,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO slice of ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO slice of null ptr"); } } else if (is_slice(array_type)) { ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); @@ -18997,6 +19152,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialBaseStruct: zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO slice const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO slice const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO slice const inner optional payload"); case ConstPtrSpecialHardCodedAddr: array_val = nullptr; abs_offset = 0; @@ -19004,6 +19165,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO slice of slice cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO slice of null"); } } else { zig_unreachable(); @@ -19069,6 +19232,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction zig_unreachable(); case ConstPtrSpecialBaseStruct: zig_panic("TODO"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO"); case ConstPtrSpecialHardCodedAddr: init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, parent_ptr->type->data.pointer.child_type, @@ -19077,6 +19246,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO"); + case ConstPtrSpecialNull: + zig_panic("TODO"); } ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; @@ -19432,7 +19603,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { - return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr)); + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + return ir_const_bool(ira, &instruction->base, (err != nullptr)); } } @@ -19458,48 +19630,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } -static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, - IrInstructionUnwrapErrCode *instruction) -{ - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) +static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { + IrInstruction *base_ptr = instruction->err_union->child; + if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_instruction; - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.err; - assert(err); - IrInstruction *result = ir_const(ira, &instruction->base, - type_entry->data.error_union.err_set_type); - result->value.data.x_err_set = err; - return result; - } - } - - IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); - result->value.type = type_entry->data.error_union.err_set_type; - return result; - } else { - ir_add_error(ira, value, + if (type_entry->id != ZigTypeIdErrorUnion) { + ir_add_error(ira, base_ptr, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + + if (instr_is_comptime(base_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + if (err_union_val == nullptr) + return ira->codegen->invalid_instruction; + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + assert(err); + + IrInstruction *result = ir_const(ira, &instruction->base, + type_entry->data.error_union.err_set_type); + result->value.data.x_err_set = err; + return result; + } + } + + IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, base_ptr); + result->value.type = type_entry->data.error_union.err_set_type; + return result; } static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, @@ -19515,48 +19686,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = type_entry->data.error_union.payload_type; - if (type_is_invalid(payload_type)) { - return ira->codegen->invalid_instruction; - } - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0); - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_instruction; - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.err; - if (err != nullptr) { - ir_add_error(ira, &instruction->base, - buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *result = ir_const(ira, &instruction->base, result_type); - result->value.data.x_ptr.special = ConstPtrSpecialRef; - result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; - return result; - } - } - - IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); - result->value.type = result_type; - return result; - } else { + if (type_entry->id != ZigTypeIdErrorUnion) { ir_add_error(ira, value, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + ZigType *payload_type = type_entry->data.error_union.payload_type; + if (type_is_invalid(payload_type)) + return ira->codegen->invalid_instruction; + + ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, + PtrLenSingle, 0, 0, 0); + if (instr_is_comptime(value)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + if (err_union_val == nullptr) + return ira->codegen->invalid_instruction; + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + if (err != nullptr) { + ir_add_error(ira, &instruction->base, + buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *result = ir_const(ira, &instruction->base, result_type); + result->value.data.x_ptr.special = ConstPtrSpecialRef; + result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; + return result; + } + } + + IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); + result->value.type = result_type; + return result; } static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { @@ -19973,7 +20144,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type); + IrInstruction *result = ir_const(ira, target, result_type); copy_const_val(&result->value, val, false); result->value.type = result_type; return result; @@ -20021,8 +20192,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, - dest_type); + IrInstruction *result = ir_const(ira, source_instr, dest_type); copy_const_val(&result->value, val, false); result->value.type = dest_type; return result; @@ -20045,9 +20215,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return ira->codegen->invalid_instruction; } - IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope, - source_instr->source_node, nullptr, ptr); - casted_ptr->value.type = dest_type; + IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -20073,7 +20241,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return result; } -static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { +static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) @@ -20211,15 +20379,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) return err; } - break; + return ErrorNone; case ConstArraySpecialUndef: zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); case ConstArraySpecialBuf: zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); } - - return ErrorNone; + zig_unreachable(); } + case ZigTypeIdEnum: + switch (val->type->data.enumeration.layout) { + case ContainerLayoutAuto: + zig_panic("TODO buf_read_value_bytes enum auto"); + case ContainerLayoutPacked: + zig_panic("TODO buf_read_value_bytes enum packed"); + case ContainerLayoutExtern: { + ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; + assert(tag_int_type->id == ZigTypeIdInt); + bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, + codegen->is_big_endian, tag_int_type->data.integral.is_signed); + return ErrorNone; + } + } + zig_unreachable(); case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { @@ -20258,8 +20440,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_panic("TODO buf_read_value_bytes error union"); case ZigTypeIdErrorSet: zig_panic("TODO buf_read_value_bytes pure error type"); - case ZigTypeIdEnum: - zig_panic("TODO buf_read_value_bytes enum type"); case ZigTypeIdFn: zig_panic("TODO buf_read_value_bytes fn type"); case ZigTypeIdUnion: @@ -20426,8 +20606,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, case TldIdContainer: case TldIdCompTime: zig_unreachable(); - case TldIdVar: - { + case TldIdVar: { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; @@ -20445,8 +20624,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, return ir_get_deref(ira, &instruction->base, var_ptr); } } - case TldIdFn: - { + case TldIdFn: { TldFn *tld_fn = (TldFn *)tld; ZigFn *fn_entry = tld_fn->fn_entry; assert(fn_entry->type_entry); @@ -20492,8 +20670,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru if (!val) return ira->codegen->invalid_instruction; if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, usize); + IrInstruction *result = ir_const(ira, &instruction->base, usize); bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); result->value.type = usize; return result; @@ -21331,6 +21508,9 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdCast: + case IrInstructionIdDeclVarGen: + case IrInstructionIdPtrCastGen: + case IrInstructionIdCmpxchgGen: zig_unreachable(); case IrInstructionIdReturn: @@ -21341,8 +21521,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); case IrInstructionIdBinOp: return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); - case IrInstructionIdDeclVar: - return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); + case IrInstructionIdDeclVarSrc: + return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction); case IrInstructionIdLoadPtr: return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); case IrInstructionIdStorePtr: @@ -21387,8 +21567,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); case IrInstructionIdTestNonNull: return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapOptional: - return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction); case IrInstructionIdClz: return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -21429,8 +21609,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); case IrInstructionIdEmbedFile: return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction); - case IrInstructionIdCmpxchg: - return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgSrc: + return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction); case IrInstructionIdFence: return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); case IrInstructionIdTruncate: @@ -21497,8 +21677,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); case IrInstructionIdPanic: return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); - case IrInstructionIdPtrCast: - return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastSrc: + return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); case IrInstructionIdBitCast: return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); case IrInstructionIdIntToPtr: @@ -21682,7 +21862,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdBr: case IrInstructionIdCondBr: case IrInstructionIdSwitchBr: - case IrInstructionIdDeclVar: + case IrInstructionIdDeclVarSrc: + case IrInstructionIdDeclVarGen: case IrInstructionIdStorePtr: case IrInstructionIdCall: case IrInstructionIdReturn: @@ -21697,7 +21878,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCInclude: case IrInstructionIdCDefine: case IrInstructionIdCUndef: - case IrInstructionIdCmpxchg: case IrInstructionIdFence: case IrInstructionIdMemset: case IrInstructionIdMemcpy: @@ -21725,6 +21905,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdMergeErrRetTraces: case IrInstructionIdMarkErrRetTracePtr: case IrInstructionIdAtomicRmw: + case IrInstructionIdCmpxchgGen: + case IrInstructionIdCmpxchgSrc: return true; case IrInstructionIdPhi: @@ -21750,7 +21932,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdTestNonNull: - case IrInstructionIdUnwrapOptional: + case IrInstructionIdOptionalUnwrapPtr: case IrInstructionIdClz: case IrInstructionIdCtz: case IrInstructionIdPopCount: @@ -21777,7 +21959,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: - case IrInstructionIdPtrCast: + case IrInstructionIdPtrCastSrc: + case IrInstructionIdPtrCastGen: case IrInstructionIdBitCast: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir.hpp b/src/ir.hpp index 7af1d7f52b..0a7c614812 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -13,7 +13,7 @@ bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); -IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, +ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b5099db86a..a3ec8e9d35 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction } } -static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) { +static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) { const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; const char *name = buf_ptr(&decl_var_instruction->var->name); if (decl_var_instruction->var_type) { @@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { } static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { - fprintf(irp->f, "*"); ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ".*"); } static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { @@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { fprintf(irp->f, ")"); } -static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { - fprintf(irp->f, "*"); +static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { ir_print_other_instruction(irp, instruction->value); fprintf(irp->f, " != null"); } -static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) { - fprintf(irp->f, "&??*"); - ir_print_other_instruction(irp, instruction->value); +static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) { + fprintf(irp->f, "&"); + ir_print_other_instruction(irp, instruction->base_ptr); + fprintf(irp->f, ".*.?"); if (!instruction->safety_check_on) { fprintf(irp->f, " // no safety"); } @@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio fprintf(irp->f, ")"); } -static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { +static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) { fprintf(irp->f, "@cmpxchg("); ir_print_other_instruction(irp, instruction->ptr); fprintf(irp->f, ", "); @@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { fprintf(irp->f, ")"); } +static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { + fprintf(irp->f, "@cmpxchg("); + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->cmp_value); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->new_value); + fprintf(irp->f, ", TODO print atomic orders)"); +} + static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { fprintf(irp->f, "@fence("); ir_print_other_instruction(irp, instruction->order_value); @@ -820,13 +830,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { } static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { - fprintf(irp->f, "@unwrapErrorCode("); - ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, "UnwrapErrorCode("); + ir_print_other_instruction(irp, instruction->err_union); fprintf(irp->f, ")"); } static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { - fprintf(irp->f, "@unwrapErrorPayload("); + fprintf(irp->f, "ErrorUnionFieldPayload("); ir_print_other_instruction(irp, instruction->value); fprintf(irp->f, ")"); if (!instruction->safety_check_on) { @@ -879,7 +889,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst fprintf(irp->f, ")"); } -static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { +static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) { fprintf(irp->f, "@ptrCast("); if (instruction->dest_type) { ir_print_other_instruction(irp, instruction->dest_type); @@ -889,6 +899,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { fprintf(irp->f, ")"); } +static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) { + fprintf(irp->f, "@ptrCast("); + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ")"); +} + static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { fprintf(irp->f, "@bitCast("); if (instruction->dest_type) { @@ -900,7 +916,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { } static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { - fprintf(irp->f, "@widenOrShorten("); + fprintf(irp->f, "WidenOrShorten("); ir_print_other_instruction(irp, instruction->target); fprintf(irp->f, ")"); } @@ -1323,6 +1339,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) { + ZigVar *var = decl_var_instruction->var; + const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; + const char *name = buf_ptr(&decl_var_instruction->var->name); + fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), + var->align_bytes); + + ir_print_other_instruction(irp, decl_var_instruction->init_value); + if (decl_var_instruction->var->is_comptime != nullptr) { + fprintf(irp->f, " // comptime = "); + ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime); + } +} + static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { fprintf(irp->f, "@bswap("); if (instruction->type != nullptr) { @@ -1361,8 +1391,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBinOp: ir_print_bin_op(irp, (IrInstructionBinOp *)instruction); break; - case IrInstructionIdDeclVar: - ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction); + case IrInstructionIdDeclVarSrc: + ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction); break; case IrInstructionIdCast: ir_print_cast(irp, (IrInstructionCast *)instruction); @@ -1452,10 +1482,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); break; case IrInstructionIdTestNonNull: - ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction); + ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction); break; - case IrInstructionIdUnwrapOptional: - ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction); break; case IrInstructionIdCtz: ir_print_ctz(irp, (IrInstructionCtz *)instruction); @@ -1508,8 +1538,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdEmbedFile: ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction); break; - case IrInstructionIdCmpxchg: - ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgSrc: + ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction); + break; + case IrInstructionIdCmpxchgGen: + ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction); break; case IrInstructionIdFence: ir_print_fence(irp, (IrInstructionFence *)instruction); @@ -1607,8 +1640,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTestComptime: ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); break; - case IrInstructionIdPtrCast: - ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastSrc: + ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction); + break; + case IrInstructionIdPtrCastGen: + ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; case IrInstructionIdBitCast: ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); @@ -1775,6 +1811,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCheckRuntimeScope: ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); break; + case IrInstructionIdDeclVarGen: + ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/parser.cpp b/src/parser.cpp index 077365995e..81bd469d1c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse else_body = ast_expect(pc, body_parser); } - assert(res->type == NodeTypeTestExpr); + assert(res->type == NodeTypeIfOptional); if (err_payload != nullptr) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; @@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { if (requires_semi && else_body == nullptr) expect_token(pc, TokenIdSemicolon); - assert(res->type == NodeTypeTestExpr); + assert(res->type == NodeTypeIfOptional); if (err_payload != nullptr) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; @@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { Optional opt_payload = ast_parse_ptr_payload(pc); PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first); + AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); res->data.test_expr.target_node = condition; if (opt_payload.unwrap(&payload)) { res->data.test_expr.var_symbol = token_buf(payload.payload); @@ -2999,7 +2999,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.if_err_expr.then_node, visit, context); visit_field(&node->data.if_err_expr.else_node, visit, context); break; - case NodeTypeTestExpr: + case NodeTypeIfOptional: visit_field(&node->data.test_expr.target_node, visit, context); visit_field(&node->data.test_expr.then_node, visit, context); visit_field(&node->data.test_expr.else_node, visit, context); diff --git a/std/event/fs.zig b/std/event/fs.zig index 1b8e1aa5dc..7e77b3e6e2 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type { const test_tmp_dir = "std_event_fs_test"; -test "write a file, watch it, write it again" { - if (builtin.os == builtin.Os.windows) { - // TODO this test is disabled on windows until the coroutine rewrite is finished. - // https://github.com/ziglang/zig/issues/1363 - return error.SkipZigTest; - } - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const allocator = &da.allocator; - - // TODO move this into event loop too - try os.makePath(allocator, test_tmp_dir); - defer os.deleteTree(allocator, test_tmp_dir) catch {}; - - var loop: Loop = undefined; - try loop.initMultiThreaded(allocator); - defer loop.deinit(); - - var result: anyerror!void = error.ResultNeverWritten; - const handle = try async testFsWatchCantFail(&loop, &result); - defer cancel handle; - - loop.run(); - return result; -} +// TODO this test is disabled until the coroutine rewrite is finished. +//test "write a file, watch it, write it again" { +// return error.SkipZigTest; +// var da = std.heap.DirectAllocator.init(); +// defer da.deinit(); +// +// const allocator = &da.allocator; +// +// // TODO move this into event loop too +// try os.makePath(allocator, test_tmp_dir); +// defer os.deleteTree(allocator, test_tmp_dir) catch {}; +// +// var loop: Loop = undefined; +// try loop.initMultiThreaded(allocator); +// defer loop.deinit(); +// +// var result: anyerror!void = error.ResultNeverWritten; +// const handle = try async testFsWatchCantFail(&loop, &result); +// defer cancel handle; +// +// loop.run(); +// return result; +//} async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { result.* = await (async testFsWatch(loop) catch unreachable); diff --git a/test/behavior.zig b/test/behavior.zig deleted file mode 100644 index 10cd08dad7..0000000000 --- a/test/behavior.zig +++ /dev/null @@ -1,82 +0,0 @@ -const builtin = @import("builtin"); - -comptime { - _ = @import("cases/align.zig"); - _ = @import("cases/alignof.zig"); - _ = @import("cases/array.zig"); - _ = @import("cases/asm.zig"); - _ = @import("cases/atomics.zig"); - _ = @import("cases/bitcast.zig"); - _ = @import("cases/bool.zig"); - _ = @import("cases/bswap.zig"); - _ = @import("cases/bitreverse.zig"); - _ = @import("cases/bugs/1076.zig"); - _ = @import("cases/bugs/1111.zig"); - _ = @import("cases/bugs/1277.zig"); - _ = @import("cases/bugs/1322.zig"); - _ = @import("cases/bugs/1381.zig"); - _ = @import("cases/bugs/1421.zig"); - _ = @import("cases/bugs/1442.zig"); - _ = @import("cases/bugs/1486.zig"); - _ = @import("cases/bugs/394.zig"); - _ = @import("cases/bugs/655.zig"); - _ = @import("cases/bugs/656.zig"); - _ = @import("cases/bugs/726.zig"); - _ = @import("cases/bugs/828.zig"); - _ = @import("cases/bugs/920.zig"); - _ = @import("cases/byval_arg_var.zig"); - _ = @import("cases/cancel.zig"); - _ = @import("cases/cast.zig"); - _ = @import("cases/const_slice_child.zig"); - _ = @import("cases/coroutine_await_struct.zig"); - _ = @import("cases/coroutines.zig"); - _ = @import("cases/defer.zig"); - _ = @import("cases/enum.zig"); - _ = @import("cases/enum_with_members.zig"); - _ = @import("cases/error.zig"); - _ = @import("cases/eval.zig"); - _ = @import("cases/field_parent_ptr.zig"); - _ = @import("cases/fn.zig"); - _ = @import("cases/fn_in_struct_in_comptime.zig"); - _ = @import("cases/for.zig"); - _ = @import("cases/generics.zig"); - _ = @import("cases/if.zig"); - _ = @import("cases/import.zig"); - _ = @import("cases/incomplete_struct_param_tld.zig"); - _ = @import("cases/inttoptr.zig"); - _ = @import("cases/ir_block_deps.zig"); - _ = @import("cases/math.zig"); - _ = @import("cases/merge_error_sets.zig"); - _ = @import("cases/misc.zig"); - _ = @import("cases/namespace_depends_on_compile_var/index.zig"); - _ = @import("cases/new_stack_call.zig"); - _ = @import("cases/null.zig"); - _ = @import("cases/optional.zig"); - _ = @import("cases/pointers.zig"); - _ = @import("cases/popcount.zig"); - _ = @import("cases/ptrcast.zig"); - _ = @import("cases/pub_enum/index.zig"); - _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); - _ = @import("cases/reflection.zig"); - _ = @import("cases/sizeof_and_typeof.zig"); - _ = @import("cases/slice.zig"); - _ = @import("cases/struct.zig"); - _ = @import("cases/struct_contains_null_ptr_itself.zig"); - _ = @import("cases/struct_contains_slice_of_itself.zig"); - _ = @import("cases/switch.zig"); - _ = @import("cases/switch_prong_err_enum.zig"); - _ = @import("cases/switch_prong_implicit_cast.zig"); - _ = @import("cases/syntax.zig"); - _ = @import("cases/this.zig"); - _ = @import("cases/truncate.zig"); - _ = @import("cases/try.zig"); - _ = @import("cases/type_info.zig"); - _ = @import("cases/undefined.zig"); - _ = @import("cases/underscore.zig"); - _ = @import("cases/union.zig"); - _ = @import("cases/var_args.zig"); - _ = @import("cases/void.zig"); - _ = @import("cases/while.zig"); - _ = @import("cases/widening.zig"); - _ = @import("cases/bit_shifting.zig"); -} diff --git a/test/cases/array.zig b/test/cases/array.zig deleted file mode 100644 index 7c63a649a8..0000000000 --- a/test/cases/array.zig +++ /dev/null @@ -1,173 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -test "arrays" { - var array: [5]u32 = undefined; - - var i: u32 = 0; - while (i < 5) { - array[i] = i + 1; - i = array[i]; - } - - i = 0; - var accumulator = u32(0); - while (i < 5) { - accumulator += array[i]; - - i += 1; - } - - assert(accumulator == 15); - assert(getArrayLen(array) == 5); -} -fn getArrayLen(a: []const u32) usize { - return a.len; -} - -test "void arrays" { - var array: [4]void = undefined; - array[0] = void{}; - array[1] = array[2]; - assert(@sizeOf(@typeOf(array)) == 0); - assert(array.len == 4); -} - -test "array literal" { - const hex_mult = []u16{ - 4096, - 256, - 16, - 1, - }; - - assert(hex_mult.len == 4); - assert(hex_mult[1] == 256); -} - -test "array dot len const expr" { - assert(comptime x: { - break :x some_array.len == 4; - }); -} - -const ArrayDotLenConstExpr = struct { - y: [some_array.len]u8, -}; -const some_array = []u8{ - 0, - 1, - 2, - 3, -}; - -test "nested arrays" { - const array_of_strings = [][]const u8{ - "hello", - "this", - "is", - "my", - "thing", - }; - for (array_of_strings) |s, i| { - if (i == 0) assert(mem.eql(u8, s, "hello")); - if (i == 1) assert(mem.eql(u8, s, "this")); - if (i == 2) assert(mem.eql(u8, s, "is")); - if (i == 3) assert(mem.eql(u8, s, "my")); - if (i == 4) assert(mem.eql(u8, s, "thing")); - } -} - -var s_array: [8]Sub = undefined; -const Sub = struct { - b: u8, -}; -const Str = struct { - a: []Sub, -}; -test "set global var array via slice embedded in struct" { - var s = Str{ .a = s_array[0..] }; - - s.a[0].b = 1; - s.a[1].b = 2; - s.a[2].b = 3; - - assert(s_array[0].b == 1); - assert(s_array[1].b == 2); - assert(s_array[2].b == 3); -} - -test "array literal with specified size" { - var array = [2]u8{ - 1, - 2, - }; - assert(array[0] == 1); - assert(array[1] == 2); -} - -test "array child property" { - var x: [5]i32 = undefined; - assert(@typeOf(x).Child == i32); -} - -test "array len property" { - var x: [5]i32 = undefined; - assert(@typeOf(x).len == 5); -} - -test "array len field" { - var arr = [4]u8{ 0, 0, 0, 0 }; - var ptr = &arr; - assert(arr.len == 4); - comptime assert(arr.len == 4); - assert(ptr.len == 4); - comptime assert(ptr.len == 4); -} - -test "single-item pointer to array indexing and slicing" { - testSingleItemPtrArrayIndexSlice(); - comptime testSingleItemPtrArrayIndexSlice(); -} - -fn testSingleItemPtrArrayIndexSlice() void { - var array = "aaaa"; - doSomeMangling(&array); - assert(mem.eql(u8, "azya", array)); -} - -fn doSomeMangling(array: *[4]u8) void { - array[1] = 'z'; - array[2..3][0] = 'y'; -} - -test "implicit cast single-item pointer" { - testImplicitCastSingleItemPtr(); - comptime testImplicitCastSingleItemPtr(); -} - -fn testImplicitCastSingleItemPtr() void { - var byte: u8 = 100; - const slice = (*[1]u8)(&byte)[0..]; - slice[0] += 1; - assert(byte == 101); -} - -fn testArrayByValAtComptime(b: [2]u8) u8 { - return b[0]; -} - -test "comptime evalutating function that takes array by value" { - const arr = []u8{ 0, 1 }; - _ = comptime testArrayByValAtComptime(arr); - _ = comptime testArrayByValAtComptime(arr); -} - -test "implicit comptime in array type size" { - var arr: [plusOne(10)]bool = undefined; - assert(arr.len == 11); -} - -fn plusOne(x: u32) u32 { - return x + 1; -} diff --git a/test/cases/asm.zig b/test/cases/asm.zig deleted file mode 100644 index 63e37c857c..0000000000 --- a/test/cases/asm.zig +++ /dev/null @@ -1,48 +0,0 @@ -const config = @import("builtin"); -const assert = @import("std").debug.assert; - -comptime { - if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - asm volatile ( - \\.globl aoeu; - \\.type aoeu, @function; - \\.set aoeu, derp; - ); - } -} - -test "module level assembly" { - if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(aoeu() == 1234); - } -} - -test "output constraint modifiers" { - // This is only testing compilation. - var a: u32 = 3; - asm volatile ("" : [_]"=m,r"(a) : : ""); - asm volatile ("" : [_]"=r,m"(a) : : ""); -} - -test "alternative constraints" { - // Make sure we allow commas as a separator for alternative constraints. - var a: u32 = 3; - asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : ""); -} - -test "sized integer/float in asm input" { - asm volatile ("" : : [_]"m"(usize(3)) : ""); - asm volatile ("" : : [_]"m"(i15(-3)) : ""); - asm volatile ("" : : [_]"m"(u3(3)) : ""); - asm volatile ("" : : [_]"m"(i3(3)) : ""); - asm volatile ("" : : [_]"m"(u121(3)) : ""); - asm volatile ("" : : [_]"m"(i121(3)) : ""); - asm volatile ("" : : [_]"m"(f32(3.17)) : ""); - asm volatile ("" : : [_]"m"(f64(3.17)) : ""); -} - -extern fn aoeu() i32; - -export fn derp() i32 { - return 1234; -} diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig deleted file mode 100644 index 3721e68a94..0000000000 --- a/test/cases/bitreverse.zig +++ /dev/null @@ -1,81 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const minInt = std.math.minInt; - -test "@bitreverse" { - comptime testBitReverse(); - testBitReverse(); -} - -fn testBitReverse() void { - // using comptime_ints, unsigned - assert(@bitreverse(u0, 0) == 0); - assert(@bitreverse(u5, 0x12) == 0x9); - assert(@bitreverse(u8, 0x12) == 0x48); - assert(@bitreverse(u16, 0x1234) == 0x2c48); - assert(@bitreverse(u24, 0x123456) == 0x6a2c48); - assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); - assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); - assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); - assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); - assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); - assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); - - // using runtime uints, unsigned - var num0: u0 = 0; - assert(@bitreverse(u0, num0) == 0); - var num5: u5 = 0x12; - assert(@bitreverse(u5, num5) == 0x9); - var num8: u8 = 0x12; - assert(@bitreverse(u8, num8) == 0x48); - var num16: u16 = 0x1234; - assert(@bitreverse(u16, num16) == 0x2c48); - var num24: u24 = 0x123456; - assert(@bitreverse(u24, num24) == 0x6a2c48); - var num32: u32 = 0x12345678; - assert(@bitreverse(u32, num32) == 0x1e6a2c48); - var num40: u40 = 0x123456789a; - assert(@bitreverse(u40, num40) == 0x591e6a2c48); - var num48: u48 = 0x123456789abc; - assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); - var num56: u56 = 0x123456789abcde; - assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); - var num64: u64 = 0x123456789abcdef1; - assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); - var num128: u128 = 0x123456789abcdef11121314151617181; - assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); - - // using comptime_ints, signed, positive - assert(@bitreverse(i0, 0) == 0); - assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); - assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); - assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); - assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); - assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); - assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); - assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); - assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); - assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); - - // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. - var neg5: i5 = minInt(i5) + 1; - assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); - var neg8: i8 = -18; - assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); - var neg16: i16 = -32694; - assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); - var neg24: i24 = -6773785; - assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); - var neg32: i32 = -16773785; - assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); - var neg40: i40 = minInt(i40) + 12345; - assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); - var neg48: i48 = minInt(i48) + 12345; - assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); - var neg56: i56 = minInt(i56) + 12345; - assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); - var neg64: i64 = minInt(i64) + 12345; - assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); - var neg128: i128 = minInt(i128) + 12345; - assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); -} diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig deleted file mode 100644 index 57993077e1..0000000000 --- a/test/cases/bswap.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "@bswap" { - comptime testByteSwap(); - testByteSwap(); -} - -fn testByteSwap() void { - assert(@bswap(u0, 0) == 0); - assert(@bswap(u8, 0x12) == 0x12); - assert(@bswap(u16, 0x1234) == 0x3412); - assert(@bswap(u24, 0x123456) == 0x563412); - assert(@bswap(u32, 0x12345678) == 0x78563412); - assert(@bswap(u40, 0x123456789a) == 0x9a78563412); - assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); - assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); - assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); - assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); - - assert(@bswap(i0, 0) == 0); - assert(@bswap(i8, -50) == -50); - assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); - assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); - assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); - assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); - assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); - assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); - assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); - assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == - @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); -} diff --git a/test/cases/import.zig b/test/cases/import.zig deleted file mode 100644 index 6d6d4b0208..0000000000 --- a/test/cases/import.zig +++ /dev/null @@ -1,10 +0,0 @@ -const assert = @import("std").debug.assert; -const a_namespace = @import("import/a_namespace.zig"); - -test "call fn via namespace lookup" { - assert(a_namespace.foo() == 1234); -} - -test "importing the same thing gives the same import" { - assert(@import("std") == @import("std")); -} diff --git a/test/cases/optional.zig b/test/cases/optional.zig deleted file mode 100644 index d43682bbec..0000000000 --- a/test/cases/optional.zig +++ /dev/null @@ -1,30 +0,0 @@ -const assert = @import("std").debug.assert; - -pub const EmptyStruct = struct {}; - -test "optional pointer to size zero struct" { - var e = EmptyStruct{}; - var o: ?*EmptyStruct = &e; - assert(o != null); -} - -test "equality compare nullable pointers" { - testNullPtrsEql(); - comptime testNullPtrsEql(); -} - -fn testNullPtrsEql() void { - var number: i32 = 1234; - - var x: ?*i32 = null; - var y: ?*i32 = null; - assert(x == y); - y = &number; - assert(x != y); - assert(x != &number); - assert(&number != x); - x = &number; - assert(x == y); - assert(x == &number); - assert(&number == x); -} diff --git a/test/cases/popcount.zig b/test/cases/popcount.zig deleted file mode 100644 index 7dc7f28c0e..0000000000 --- a/test/cases/popcount.zig +++ /dev/null @@ -1,24 +0,0 @@ -const assert = @import("std").debug.assert; - -test "@popCount" { - comptime testPopCount(); - testPopCount(); -} - -fn testPopCount() void { - { - var x: u32 = 0xaa; - assert(@popCount(x) == 4); - } - { - var x: u32 = 0xaaaaaaaa; - assert(@popCount(x) == 16); - } - { - var x: i16 = -1; - assert(@popCount(x) == 16); - } - comptime { - assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); - } -} diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig deleted file mode 100644 index b9b8aff4e1..0000000000 --- a/test/cases/reflection.zig +++ /dev/null @@ -1,95 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const reflection = @This(); - -test "reflection: array, pointer, optional, error union type child" { - comptime { - assert(([10]u8).Child == u8); - assert((*u8).Child == u8); - assert((anyerror!u8).Payload == u8); - assert((?u8).Child == u8); - } -} - -test "reflection: function return type, var args, and param types" { - comptime { - assert(@typeOf(dummy).ReturnType == i32); - assert(!@typeOf(dummy).is_var_args); - assert(@typeOf(dummy_varargs).is_var_args); - assert(@typeOf(dummy).arg_count == 3); - assert(@ArgType(@typeOf(dummy), 0) == bool); - assert(@ArgType(@typeOf(dummy), 1) == i32); - assert(@ArgType(@typeOf(dummy), 2) == f32); - } -} - -fn dummy(a: bool, b: i32, c: f32) i32 { - return 1234; -} -fn dummy_varargs(args: ...) void {} - -test "reflection: struct member types and names" { - comptime { - assert(@memberCount(Foo) == 3); - - assert(@memberType(Foo, 0) == i32); - assert(@memberType(Foo, 1) == bool); - assert(@memberType(Foo, 2) == void); - - assert(mem.eql(u8, @memberName(Foo, 0), "one")); - assert(mem.eql(u8, @memberName(Foo, 1), "two")); - assert(mem.eql(u8, @memberName(Foo, 2), "three")); - } -} - -test "reflection: enum member types and names" { - comptime { - assert(@memberCount(Bar) == 4); - - assert(@memberType(Bar, 0) == void); - assert(@memberType(Bar, 1) == i32); - assert(@memberType(Bar, 2) == bool); - assert(@memberType(Bar, 3) == f64); - - assert(mem.eql(u8, @memberName(Bar, 0), "One")); - assert(mem.eql(u8, @memberName(Bar, 1), "Two")); - assert(mem.eql(u8, @memberName(Bar, 2), "Three")); - assert(mem.eql(u8, @memberName(Bar, 3), "Four")); - } -} - -test "reflection: @field" { - var f = Foo{ - .one = 42, - .two = true, - .three = void{}, - }; - - assert(f.one == f.one); - assert(@field(f, "o" ++ "ne") == f.one); - assert(@field(f, "t" ++ "wo") == f.two); - assert(@field(f, "th" ++ "ree") == f.three); - assert(@field(Foo, "const" ++ "ant") == Foo.constant); - assert(@field(Bar, "O" ++ "ne") == Bar.One); - assert(@field(Bar, "T" ++ "wo") == Bar.Two); - assert(@field(Bar, "Th" ++ "ree") == Bar.Three); - assert(@field(Bar, "F" ++ "our") == Bar.Four); - assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); - @field(f, "o" ++ "ne") = 4; - assert(f.one == 4); -} - -const Foo = struct { - const constant = 52; - - one: i32, - two: bool, - three: void, -}; - -const Bar = union(enum) { - One: void, - Two: i32, - Three: bool, - Four: f64, -}; diff --git a/test/cases/sizeof_and_typeof.zig b/test/cases/sizeof_and_typeof.zig deleted file mode 100644 index 11c6b2f6ba..0000000000 --- a/test/cases/sizeof_and_typeof.zig +++ /dev/null @@ -1,69 +0,0 @@ -const builtin = @import("builtin"); -const assert = @import("std").debug.assert; - -test "@sizeOf and @typeOf" { - const y: @typeOf(x) = 120; - assert(@sizeOf(@typeOf(y)) == 2); -} -const x: u16 = 13; -const z: @typeOf(x) = 19; - -const A = struct { - a: u8, - b: u32, - c: u8, - d: u3, - e: u5, - f: u16, - g: u16, -}; - -const P = packed struct { - a: u8, - b: u32, - c: u8, - d: u3, - e: u5, - f: u16, - g: u16, -}; - -test "@byteOffsetOf" { - // Packed structs have fixed memory layout - assert(@byteOffsetOf(P, "a") == 0); - assert(@byteOffsetOf(P, "b") == 1); - assert(@byteOffsetOf(P, "c") == 5); - assert(@byteOffsetOf(P, "d") == 6); - assert(@byteOffsetOf(P, "e") == 6); - assert(@byteOffsetOf(P, "f") == 7); - assert(@byteOffsetOf(P, "g") == 9); - - // Normal struct fields can be moved/padded - var a: A = undefined; - assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); - assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); - assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); - assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); - assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); - assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); - assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); -} - -test "@bitOffsetOf" { - // Packed structs have fixed memory layout - assert(@bitOffsetOf(P, "a") == 0); - assert(@bitOffsetOf(P, "b") == 8); - assert(@bitOffsetOf(P, "c") == 40); - assert(@bitOffsetOf(P, "d") == 48); - assert(@bitOffsetOf(P, "e") == 51); - assert(@bitOffsetOf(P, "f") == 56); - assert(@bitOffsetOf(P, "g") == 72); - - assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); - assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); - assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); - assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); - assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); - assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); - assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); -} diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig deleted file mode 100644 index cec532d5d3..0000000000 --- a/test/cases/type_info.zig +++ /dev/null @@ -1,264 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const TypeInfo = @import("builtin").TypeInfo; -const TypeId = @import("builtin").TypeId; - -test "type info: tag type, void info" { - testBasic(); - comptime testBasic(); -} - -fn testBasic() void { - assert(@TagType(TypeInfo) == TypeId); - const void_info = @typeInfo(void); - assert(TypeId(void_info) == TypeId.Void); - assert(void_info.Void == {}); -} - -test "type info: integer, floating point type info" { - testIntFloat(); - comptime testIntFloat(); -} - -fn testIntFloat() void { - const u8_info = @typeInfo(u8); - assert(TypeId(u8_info) == TypeId.Int); - assert(!u8_info.Int.is_signed); - assert(u8_info.Int.bits == 8); - - const f64_info = @typeInfo(f64); - assert(TypeId(f64_info) == TypeId.Float); - assert(f64_info.Float.bits == 64); -} - -test "type info: pointer type info" { - testPointer(); - comptime testPointer(); -} - -fn testPointer() void { - const u32_ptr_info = @typeInfo(*u32); - assert(TypeId(u32_ptr_info) == TypeId.Pointer); - assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); - assert(u32_ptr_info.Pointer.is_const == false); - assert(u32_ptr_info.Pointer.is_volatile == false); - assert(u32_ptr_info.Pointer.alignment == @alignOf(u32)); - assert(u32_ptr_info.Pointer.child == u32); -} - -test "type info: unknown length pointer type info" { - testUnknownLenPtr(); - comptime testUnknownLenPtr(); -} - -fn testUnknownLenPtr() void { - const u32_ptr_info = @typeInfo([*]const volatile f64); - assert(TypeId(u32_ptr_info) == TypeId.Pointer); - assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); - assert(u32_ptr_info.Pointer.is_const == true); - assert(u32_ptr_info.Pointer.is_volatile == true); - assert(u32_ptr_info.Pointer.alignment == @alignOf(f64)); - assert(u32_ptr_info.Pointer.child == f64); -} - -test "type info: slice type info" { - testSlice(); - comptime testSlice(); -} - -fn testSlice() void { - const u32_slice_info = @typeInfo([]u32); - assert(TypeId(u32_slice_info) == TypeId.Pointer); - assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); - assert(u32_slice_info.Pointer.is_const == false); - assert(u32_slice_info.Pointer.is_volatile == false); - assert(u32_slice_info.Pointer.alignment == 4); - assert(u32_slice_info.Pointer.child == u32); -} - -test "type info: array type info" { - testArray(); - comptime testArray(); -} - -fn testArray() void { - const arr_info = @typeInfo([42]bool); - assert(TypeId(arr_info) == TypeId.Array); - assert(arr_info.Array.len == 42); - assert(arr_info.Array.child == bool); -} - -test "type info: optional type info" { - testOptional(); - comptime testOptional(); -} - -fn testOptional() void { - const null_info = @typeInfo(?void); - assert(TypeId(null_info) == TypeId.Optional); - assert(null_info.Optional.child == void); -} - -test "type info: promise info" { - testPromise(); - comptime testPromise(); -} - -fn testPromise() void { - const null_promise_info = @typeInfo(promise); - assert(TypeId(null_promise_info) == TypeId.Promise); - assert(null_promise_info.Promise.child == null); - - const promise_info = @typeInfo(promise->usize); - assert(TypeId(promise_info) == TypeId.Promise); - assert(promise_info.Promise.child.? == usize); -} - -test "type info: error set, error union info" { - testErrorSet(); - comptime testErrorSet(); -} - -fn testErrorSet() void { - const TestErrorSet = error{ - First, - Second, - Third, - }; - - const error_set_info = @typeInfo(TestErrorSet); - assert(TypeId(error_set_info) == TypeId.ErrorSet); - assert(error_set_info.ErrorSet.errors.len == 3); - assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); - assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); - - const error_union_info = @typeInfo(TestErrorSet!usize); - assert(TypeId(error_union_info) == TypeId.ErrorUnion); - assert(error_union_info.ErrorUnion.error_set == TestErrorSet); - assert(error_union_info.ErrorUnion.payload == usize); -} - -test "type info: enum info" { - testEnum(); - comptime testEnum(); -} - -fn testEnum() void { - const Os = enum { - Windows, - Macos, - Linux, - FreeBSD, - }; - - const os_info = @typeInfo(Os); - assert(TypeId(os_info) == TypeId.Enum); - assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assert(os_info.Enum.fields.len == 4); - assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); - assert(os_info.Enum.fields[3].value == 3); - assert(os_info.Enum.tag_type == u2); - assert(os_info.Enum.defs.len == 0); -} - -test "type info: union info" { - testUnion(); - comptime testUnion(); -} - -fn testUnion() void { - const typeinfo_info = @typeInfo(TypeInfo); - assert(TypeId(typeinfo_info) == TypeId.Union); - assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(typeinfo_info.Union.tag_type.? == TypeId); - assert(typeinfo_info.Union.fields.len == 24); - assert(typeinfo_info.Union.fields[4].enum_field != null); - assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4); - assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assert(typeinfo_info.Union.defs.len == 20); - - const TestNoTagUnion = union { - Foo: void, - Bar: u32, - }; - - const notag_union_info = @typeInfo(TestNoTagUnion); - assert(TypeId(notag_union_info) == TypeId.Union); - assert(notag_union_info.Union.tag_type == null); - assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(notag_union_info.Union.fields.len == 2); - assert(notag_union_info.Union.fields[0].enum_field == null); - assert(notag_union_info.Union.fields[1].field_type == u32); - - const TestExternUnion = extern union { - foo: *c_void, - }; - - const extern_union_info = @typeInfo(TestExternUnion); - assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); - assert(extern_union_info.Union.tag_type == null); - assert(extern_union_info.Union.fields[0].enum_field == null); - assert(extern_union_info.Union.fields[0].field_type == *c_void); -} - -test "type info: struct info" { - testStruct(); - comptime testStruct(); -} - -fn testStruct() void { - const struct_info = @typeInfo(TestStruct); - assert(TypeId(struct_info) == TypeId.Struct); - assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); - assert(struct_info.Struct.fields.len == 3); - assert(struct_info.Struct.fields[1].offset == null); - assert(struct_info.Struct.fields[2].field_type == *TestStruct); - assert(struct_info.Struct.defs.len == 2); - assert(struct_info.Struct.defs[0].is_pub); - assert(!struct_info.Struct.defs[0].data.Fn.is_extern); - assert(struct_info.Struct.defs[0].data.Fn.lib_name == null); - assert(struct_info.Struct.defs[0].data.Fn.return_type == void); - assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); -} - -const TestStruct = packed struct { - const Self = @This(); - - fieldA: usize, - fieldB: void, - fieldC: *Self, - - pub fn foo(self: *const Self) void {} -}; - -test "type info: function type info" { - testFunction(); - comptime testFunction(); -} - -fn testFunction() void { - const fn_info = @typeInfo(@typeOf(foo)); - assert(TypeId(fn_info) == TypeId.Fn); - assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); - assert(fn_info.Fn.is_generic); - assert(fn_info.Fn.args.len == 2); - assert(fn_info.Fn.is_var_args); - assert(fn_info.Fn.return_type == null); - assert(fn_info.Fn.async_allocator_type == null); - - const test_instance: TestStruct = undefined; - const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); - assert(TypeId(bound_fn_info) == TypeId.BoundFn); - assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); -} - -fn foo(comptime a: usize, b: bool, args: ...) usize { - return 0; -} - -test "typeInfo with comptime parameter in struct fn def" { - const S = struct { - pub fn func(comptime x: f32) void {} - }; - comptime var info = @typeInfo(S); -} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 0754f223e8..bc1ef660c3 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3220,7 +3220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return 2; \\} , - ".tmp_source.zig:2:15: error: unable to infer expression type", + ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known", ); cases.add( @@ -3566,7 +3566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - ".tmp_source.zig:2:11: error: expected type, found 'i32'", + ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'", ); cases.add( diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig new file mode 100644 index 0000000000..e545a4c418 --- /dev/null +++ b/test/stage1/behavior.zig @@ -0,0 +1,80 @@ +comptime { + _ = @import("behavior/align.zig"); + _ = @import("behavior/alignof.zig"); + _ = @import("behavior/array.zig"); + _ = @import("behavior/asm.zig"); + _ = @import("behavior/atomics.zig"); + _ = @import("behavior/bit_shifting.zig"); + _ = @import("behavior/bitcast.zig"); + _ = @import("behavior/bitreverse.zig"); + _ = @import("behavior/bool.zig"); + _ = @import("behavior/bswap.zig"); + _ = @import("behavior/bugs/1076.zig"); + _ = @import("behavior/bugs/1111.zig"); + _ = @import("behavior/bugs/1277.zig"); + _ = @import("behavior/bugs/1322.zig"); + _ = @import("behavior/bugs/1381.zig"); + _ = @import("behavior/bugs/1421.zig"); + _ = @import("behavior/bugs/1442.zig"); + _ = @import("behavior/bugs/1486.zig"); + _ = @import("behavior/bugs/394.zig"); + _ = @import("behavior/bugs/655.zig"); + _ = @import("behavior/bugs/656.zig"); + _ = @import("behavior/bugs/726.zig"); + _ = @import("behavior/bugs/828.zig"); + _ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/byval_arg_var.zig"); + _ = @import("behavior/cancel.zig"); + _ = @import("behavior/cast.zig"); + _ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/coroutine_await_struct.zig"); + _ = @import("behavior/coroutines.zig"); + _ = @import("behavior/defer.zig"); + _ = @import("behavior/enum.zig"); + _ = @import("behavior/enum_with_members.zig"); + _ = @import("behavior/error.zig"); + _ = @import("behavior/eval.zig"); + _ = @import("behavior/field_parent_ptr.zig"); + _ = @import("behavior/fn.zig"); + _ = @import("behavior/fn_in_struct_in_comptime.zig"); + _ = @import("behavior/for.zig"); + _ = @import("behavior/generics.zig"); + _ = @import("behavior/if.zig"); + _ = @import("behavior/import.zig"); + _ = @import("behavior/incomplete_struct_param_tld.zig"); + _ = @import("behavior/inttoptr.zig"); + _ = @import("behavior/ir_block_deps.zig"); + _ = @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/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/ref_var_in_if_after_if_2nd_switch_prong.zig"); + _ = @import("behavior/reflection.zig"); + _ = @import("behavior/sizeof_and_typeof.zig"); + _ = @import("behavior/slice.zig"); + _ = @import("behavior/struct.zig"); + _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/struct_contains_slice_of_itself.zig"); + _ = @import("behavior/switch.zig"); + _ = @import("behavior/switch_prong_err_enum.zig"); + _ = @import("behavior/switch_prong_implicit_cast.zig"); + _ = @import("behavior/syntax.zig"); + _ = @import("behavior/this.zig"); + _ = @import("behavior/truncate.zig"); + _ = @import("behavior/try.zig"); + _ = @import("behavior/type_info.zig"); + _ = @import("behavior/undefined.zig"); + _ = @import("behavior/underscore.zig"); + _ = @import("behavior/union.zig"); + _ = @import("behavior/var_args.zig"); + _ = @import("behavior/void.zig"); + _ = @import("behavior/while.zig"); + _ = @import("behavior/widening.zig"); +} diff --git a/test/cases/align.zig b/test/stage1/behavior/align.zig similarity index 69% rename from test/cases/align.zig rename to test/stage1/behavior/align.zig index 3dff57feb8..aa7a93ad84 100644 --- a/test/cases/align.zig +++ b/test/stage1/behavior/align.zig @@ -1,13 +1,13 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const builtin = @import("builtin"); var foo: u8 align(4) = 100; test "global variable alignment" { - assert(@typeOf(&foo).alignment == 4); - assert(@typeOf(&foo) == *align(4) u8); + assertOrPanic(@typeOf(&foo).alignment == 4); + assertOrPanic(@typeOf(&foo) == *align(4) u8); const slice = (*[1]u8)(&foo)[0..]; - assert(@typeOf(slice) == []align(4) u8); + assertOrPanic(@typeOf(slice) == []align(4) u8); } fn derp() align(@sizeOf(usize) * 2) i32 { @@ -17,9 +17,9 @@ fn noop1() align(1) void {} fn noop4() align(4) void {} test "function alignment" { - assert(derp() == 1234); - assert(@typeOf(noop1) == fn () align(1) void); - assert(@typeOf(noop4) == fn () align(4) void); + assertOrPanic(derp() == 1234); + assertOrPanic(@typeOf(noop1) == fn () align(1) void); + assertOrPanic(@typeOf(noop4) == fn () align(4) void); noop1(); noop4(); } @@ -30,7 +30,7 @@ var baz: packed struct { } = undefined; test "packed struct alignment" { - assert(@typeOf(&baz.b) == *align(1) u32); + assertOrPanic(@typeOf(&baz.b) == *align(1) u32); } const blah: packed struct { @@ -40,17 +40,17 @@ const blah: packed struct { } = undefined; test "bit field alignment" { - assert(@typeOf(&blah.b) == *align(1:3:1) const u3); + assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3); } test "default alignment allows unspecified in type syntax" { - assert(*u32 == *align(@alignOf(u32)) u32); + assertOrPanic(*u32 == *align(@alignOf(u32)) u32); } test "implicitly decreasing pointer alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assert(addUnaligned(&a, &b) == 7); + assertOrPanic(addUnaligned(&a, &b) == 7); } fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { @@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { test "implicitly decreasing slice alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); + assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); } fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; @@ -77,7 +77,7 @@ fn testBytesAlign(b: u8) void { b, }; const ptr = @ptrCast(*u32, &bytes[0]); - assert(ptr.* == 0x33333333); + assertOrPanic(ptr.* == 0x33333333); } test "specifying alignment allows slice cast" { @@ -91,13 +91,13 @@ fn testBytesAlignSlice(b: u8) void { b, }; const slice: []u32 = @bytesToSlice(u32, bytes[0..]); - assert(slice[0] == 0x33333333); + assertOrPanic(slice[0] == 0x33333333); } test "@alignCast pointers" { var x: u32 align(4) = 1; expectsOnly1(&x); - assert(x == 2); + assertOrPanic(x == 2); } fn expectsOnly1(x: *align(1) u32) void { expects4(@alignCast(4, x)); @@ -113,7 +113,7 @@ test "@alignCast slices" { }; const slice = array[0..]; sliceExpectsOnly1(slice); - assert(slice[0] == 2); + assertOrPanic(slice[0] == 2); } fn sliceExpectsOnly1(slice: []align(1) u32) void { sliceExpects4(@alignCast(4, slice)); @@ -128,7 +128,7 @@ test "implicitly decreasing fn alignment" { } fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { - assert(ptr() == answer); + assertOrPanic(ptr() == answer); } fn alignedSmall() align(8) i32 { @@ -139,7 +139,7 @@ fn alignedBig() align(16) i32 { } test "@alignCast functions" { - assert(fnExpectsOnly1(simple4) == 0x19); + assertOrPanic(fnExpectsOnly1(simple4) == 0x19); } fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { return fnExpects4(@alignCast(4, ptr)); @@ -152,9 +152,9 @@ fn simple4() align(4) i32 { } test "generic function with align param" { - assert(whyWouldYouEverDoThis(1) == 0x1); - assert(whyWouldYouEverDoThis(4) == 0x1); - assert(whyWouldYouEverDoThis(8) == 0x1); + assertOrPanic(whyWouldYouEverDoThis(1) == 0x1); + assertOrPanic(whyWouldYouEverDoThis(4) == 0x1); + assertOrPanic(whyWouldYouEverDoThis(8) == 0x1); } fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { @@ -164,28 +164,28 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { test "@ptrCast preserves alignment of bigger source" { var x: u32 align(16) = 1234; const ptr = @ptrCast(*u8, &x); - assert(@typeOf(ptr) == *align(16) u8); + assertOrPanic(@typeOf(ptr) == *align(16) u8); } test "runtime known array index has best alignment possible" { // take full advantage of over-alignment var array align(4) = []u8{ 1, 2, 3, 4 }; - assert(@typeOf(&array[0]) == *align(4) u8); - assert(@typeOf(&array[1]) == *u8); - assert(@typeOf(&array[2]) == *align(2) u8); - assert(@typeOf(&array[3]) == *u8); + assertOrPanic(@typeOf(&array[0]) == *align(4) u8); + assertOrPanic(@typeOf(&array[1]) == *u8); + assertOrPanic(@typeOf(&array[2]) == *align(2) u8); + assertOrPanic(@typeOf(&array[3]) == *u8); // because align is too small but we still figure out to use 2 var bigger align(2) = []u64{ 1, 2, 3, 4 }; - assert(@typeOf(&bigger[0]) == *align(2) u64); - assert(@typeOf(&bigger[1]) == *align(2) u64); - assert(@typeOf(&bigger[2]) == *align(2) u64); - assert(@typeOf(&bigger[3]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64); // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 var smaller align(2) = []u32{ 1, 2, 3, 4 }; - comptime assert(@typeOf(smaller[0..]) == []align(2) u32); - comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32); + comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32); + comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32); testIndex(smaller[0..].ptr, 0, *align(2) u32); testIndex(smaller[0..].ptr, 1, *align(2) u32); testIndex(smaller[0..].ptr, 2, *align(2) u32); @@ -198,14 +198,14 @@ test "runtime known array index has best alignment possible" { testIndex2(array[0..].ptr, 3, *u8); } fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { - comptime assert(@typeOf(&smaller[index]) == T); + comptime assertOrPanic(@typeOf(&smaller[index]) == T); } fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { - comptime assert(@typeOf(&ptr[index]) == T); + comptime assertOrPanic(@typeOf(&ptr[index]) == T); } test "alignstack" { - assert(fnWithAlignedStack() == 1234); + assertOrPanic(fnWithAlignedStack() == 1234); } fn fnWithAlignedStack() i32 { @@ -214,7 +214,7 @@ fn fnWithAlignedStack() i32 { } test "alignment of structs" { - assert(@alignOf(struct { + assertOrPanic(@alignOf(struct { a: i32, b: *i32, }) == @alignOf(usize)); diff --git a/test/cases/alignof.zig b/test/stage1/behavior/alignof.zig similarity index 61% rename from test/cases/alignof.zig rename to test/stage1/behavior/alignof.zig index 433e86e45e..98c805908b 100644 --- a/test/cases/alignof.zig +++ b/test/stage1/behavior/alignof.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -10,8 +10,9 @@ const Foo = struct { }; test "@alignOf(T) before referencing T" { - comptime assert(@alignOf(Foo) != maxInt(usize)); + comptime assertOrPanic(@alignOf(Foo) != maxInt(usize)); if (builtin.arch == builtin.Arch.x86_64) { - comptime assert(@alignOf(Foo) == 4); + comptime assertOrPanic(@alignOf(Foo) == 4); } } + diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig new file mode 100644 index 0000000000..1183305209 --- /dev/null +++ b/test/stage1/behavior/array.zig @@ -0,0 +1,270 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +test "arrays" { + var array: [5]u32 = undefined; + + var i: u32 = 0; + while (i < 5) { + array[i] = i + 1; + i = array[i]; + } + + i = 0; + var accumulator = u32(0); + while (i < 5) { + accumulator += array[i]; + + i += 1; + } + + assertOrPanic(accumulator == 15); + assertOrPanic(getArrayLen(array) == 5); +} +fn getArrayLen(a: []const u32) usize { + return a.len; +} + +test "void arrays" { + var array: [4]void = undefined; + array[0] = void{}; + array[1] = array[2]; + assertOrPanic(@sizeOf(@typeOf(array)) == 0); + assertOrPanic(array.len == 4); +} + +test "array literal" { + const hex_mult = []u16{ + 4096, + 256, + 16, + 1, + }; + + assertOrPanic(hex_mult.len == 4); + assertOrPanic(hex_mult[1] == 256); +} + +test "array dot len const expr" { + assertOrPanic(comptime x: { + break :x some_array.len == 4; + }); +} + +const ArrayDotLenConstExpr = struct { + y: [some_array.len]u8, +}; +const some_array = []u8{ + 0, + 1, + 2, + 3, +}; + +test "nested arrays" { + const array_of_strings = [][]const u8{ + "hello", + "this", + "is", + "my", + "thing", + }; + for (array_of_strings) |s, i| { + if (i == 0) assertOrPanic(mem.eql(u8, s, "hello")); + if (i == 1) assertOrPanic(mem.eql(u8, s, "this")); + if (i == 2) assertOrPanic(mem.eql(u8, s, "is")); + if (i == 3) assertOrPanic(mem.eql(u8, s, "my")); + if (i == 4) assertOrPanic(mem.eql(u8, s, "thing")); + } +} + +var s_array: [8]Sub = undefined; +const Sub = struct { + b: u8, +}; +const Str = struct { + a: []Sub, +}; +test "set global var array via slice embedded in struct" { + var s = Str{ .a = s_array[0..] }; + + s.a[0].b = 1; + s.a[1].b = 2; + s.a[2].b = 3; + + assertOrPanic(s_array[0].b == 1); + assertOrPanic(s_array[1].b == 2); + assertOrPanic(s_array[2].b == 3); +} + +test "array literal with specified size" { + var array = [2]u8{ + 1, + 2, + }; + assertOrPanic(array[0] == 1); + assertOrPanic(array[1] == 2); +} + +test "array child property" { + var x: [5]i32 = undefined; + assertOrPanic(@typeOf(x).Child == i32); +} + +test "array len property" { + var x: [5]i32 = undefined; + assertOrPanic(@typeOf(x).len == 5); +} + +test "array len field" { + var arr = [4]u8{ 0, 0, 0, 0 }; + var ptr = &arr; + assertOrPanic(arr.len == 4); + comptime assertOrPanic(arr.len == 4); + assertOrPanic(ptr.len == 4); + comptime assertOrPanic(ptr.len == 4); +} + +test "single-item pointer to array indexing and slicing" { + testSingleItemPtrArrayIndexSlice(); + comptime testSingleItemPtrArrayIndexSlice(); +} + +fn testSingleItemPtrArrayIndexSlice() void { + var array = "aaaa"; + doSomeMangling(&array); + assertOrPanic(mem.eql(u8, "azya", array)); +} + +fn doSomeMangling(array: *[4]u8) void { + array[1] = 'z'; + array[2..3][0] = 'y'; +} + +test "implicit cast single-item pointer" { + testImplicitCastSingleItemPtr(); + comptime testImplicitCastSingleItemPtr(); +} + +fn testImplicitCastSingleItemPtr() void { + var byte: u8 = 100; + const slice = (*[1]u8)(&byte)[0..]; + slice[0] += 1; + assertOrPanic(byte == 101); +} + +fn testArrayByValAtComptime(b: [2]u8) u8 { + return b[0]; +} + +test "comptime evalutating function that takes array by value" { + const arr = []u8{ 0, 1 }; + _ = comptime testArrayByValAtComptime(arr); + _ = comptime testArrayByValAtComptime(arr); +} + +test "implicit comptime in array type size" { + var arr: [plusOne(10)]bool = undefined; + assertOrPanic(arr.len == 11); +} + +fn plusOne(x: u32) u32 { + return x + 1; +} + +test "array literal as argument to function" { + const S = struct { + fn entry(two: i32) void { + foo([]i32{ + 1, + 2, + 3, + }); + foo([]i32{ + 1, + two, + 3, + }); + foo2(true, []i32{ + 1, + 2, + 3, + }); + foo2(true, []i32{ + 1, + two, + 3, + }); + } + fn foo(x: []const i32) void { + assertOrPanic(x[0] == 1); + assertOrPanic(x[1] == 2); + assertOrPanic(x[2] == 3); + } + fn foo2(trash: bool, x: []const i32) void { + assertOrPanic(trash); + assertOrPanic(x[0] == 1); + assertOrPanic(x[1] == 2); + assertOrPanic(x[2] == 3); + } + }; + S.entry(2); + comptime S.entry(2); +} + +test "double nested array to const slice cast in array literal" { + const S = struct { + fn entry(two: i32) void { + const cases = [][]const []const i32{ + [][]const i32{[]i32{1}}, + [][]const i32{[]i32{ 2, 3 }}, + [][]const i32{ + []i32{4}, + []i32{ 5, 6, 7 }, + }, + }; + check(cases); + + const cases2 = [][]const i32{ + []i32{1}, + []i32{ two, 3 }, + }; + assertOrPanic(cases2.len == 2); + assertOrPanic(cases2[0].len == 1); + assertOrPanic(cases2[0][0] == 1); + assertOrPanic(cases2[1].len == 2); + assertOrPanic(cases2[1][0] == 2); + assertOrPanic(cases2[1][1] == 3); + + const cases3 = [][]const []const i32{ + [][]const i32{[]i32{1}}, + [][]const i32{[]i32{ two, 3 }}, + [][]const i32{ + []i32{4}, + []i32{ 5, 6, 7 }, + }, + }; + check(cases3); + } + + fn check(cases: []const []const []const i32) void { + assertOrPanic(cases.len == 3); + assertOrPanic(cases[0].len == 1); + assertOrPanic(cases[0][0].len == 1); + assertOrPanic(cases[0][0][0] == 1); + assertOrPanic(cases[1].len == 1); + assertOrPanic(cases[1][0].len == 2); + assertOrPanic(cases[1][0][0] == 2); + assertOrPanic(cases[1][0][1] == 3); + assertOrPanic(cases[2].len == 2); + assertOrPanic(cases[2][0].len == 1); + assertOrPanic(cases[2][0][0] == 4); + assertOrPanic(cases[2][1].len == 3); + assertOrPanic(cases[2][1][0] == 5); + assertOrPanic(cases[2][1][1] == 6); + assertOrPanic(cases[2][1][2] == 7); + } + }; + S.entry(2); + comptime S.entry(2); +} diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig new file mode 100644 index 0000000000..48701c5836 --- /dev/null +++ b/test/stage1/behavior/asm.zig @@ -0,0 +1,92 @@ +const config = @import("builtin"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +comptime { + if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { + asm volatile ( + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; + ); + } +} + +test "module level assembly" { + if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { + assertOrPanic(aoeu() == 1234); + } +} + +test "output constraint modifiers" { + // This is only testing compilation. + var a: u32 = 3; + asm volatile ("" + : [_] "=m,r" (a) + : + : "" + ); + asm volatile ("" + : [_] "=r,m" (a) + : + : "" + ); +} + +test "alternative constraints" { + // Make sure we allow commas as a separator for alternative constraints. + var a: u32 = 3; + asm volatile ("" + : [_] "=r,m" (a) + : [_] "r,m" (a) + : "" + ); +} + +test "sized integer/float in asm input" { + asm volatile ("" + : + : [_] "m" (usize(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i15(-3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (u3(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i3(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (u121(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i121(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (f32(3.17)) + : "" + ); + asm volatile ("" + : + : [_] "m" (f64(3.17)) + : "" + ); +} + +extern fn aoeu() i32; + +export fn derp() i32 { + return 1234; +} diff --git a/test/cases/atomics.zig b/test/stage1/behavior/atomics.zig similarity index 65% rename from test/cases/atomics.zig rename to test/stage1/behavior/atomics.zig index 67c9ab3dd1..fa3c5f29a6 100644 --- a/test/cases/atomics.zig +++ b/test/stage1/behavior/atomics.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -7,18 +7,18 @@ const AtomicOrder = builtin.AtomicOrder; test "cmpxchg" { var x: i32 = 1234; if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == 1234); + assertOrPanic(x1 == 1234); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == 1234); + assertOrPanic(x1 == 1234); } - assert(x == 5678); + assertOrPanic(x == 5678); - assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assert(x == 42); + assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + assertOrPanic(x == 42); } test "fence" { @@ -30,24 +30,24 @@ test "fence" { test "atomicrmw and atomicload" { var data: u8 = 200; testAtomicRmw(&data); - assert(data == 42); + assertOrPanic(data == 42); testAtomicLoad(&data); } fn testAtomicRmw(ptr: *u8) void { const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); - assert(prev_value == 200); + assertOrPanic(prev_value == 200); comptime { var x: i32 = 1234; const y: i32 = 12345; - assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); - assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); + assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); + assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); } } fn testAtomicLoad(ptr: *u8) void { const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); - assert(x == 42); + assertOrPanic(x == 42); } test "cmpxchg with ptr" { @@ -56,16 +56,16 @@ test "cmpxchg with ptr" { var data3: i32 = 9101; var x: *i32 = &data1; if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == &data1); + assertOrPanic(x1 == &data1); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == &data1); + assertOrPanic(x1 == &data1); } - assert(x == &data3); + assertOrPanic(x == &data3); - assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assert(x == &data2); + assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + assertOrPanic(x == &data2); } diff --git a/test/cases/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig similarity index 90% rename from test/cases/bit_shifting.zig rename to test/stage1/behavior/bit_shifting.zig index 325e765bb0..3290688358 100644 --- a/test/cases/bit_shifting.zig +++ b/test/stage1/behavior/bit_shifting.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { - assert(Key == @IntType(false, Key.bit_count)); - assert(Key.bit_count >= mask_bit_count); + assertOrPanic(Key == @IntType(false, Key.bit_count)); + assertOrPanic(Key.bit_count >= mask_bit_count); const ShardKey = @IntType(false, mask_bit_count); const shift_amount = Key.bit_count - ShardKey.bit_count; return struct { @@ -77,12 +77,12 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c var node_buffer: [node_count]Table.Node = undefined; for (node_buffer) |*node, i| { const key = @intCast(Key, i); - assert(table.get(key) == null); + assertOrPanic(table.get(key) == null); node.init(key, {}); table.put(node); } for (node_buffer) |*node, i| { - assert(table.get(@intCast(Key, i)) == node); + assertOrPanic(table.get(@intCast(Key, i)) == node); } } diff --git a/test/cases/bitcast.zig b/test/stage1/behavior/bitcast.zig similarity index 78% rename from test/cases/bitcast.zig rename to test/stage1/behavior/bitcast.zig index d85a84ed22..19030255e4 100644 --- a/test/cases/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const maxInt = std.math.maxInt; test "@bitCast i32 -> u32" { @@ -8,8 +8,8 @@ test "@bitCast i32 -> u32" { } fn testBitCast_i32_u32() void { - assert(conv(-1) == maxInt(u32)); - assert(conv2(maxInt(u32)) == -1); + assertOrPanic(conv(-1) == maxInt(u32)); + assertOrPanic(conv2(maxInt(u32)) == -1); } fn conv(x: i32) u32 { @@ -27,11 +27,10 @@ test "@bitCast extern enum to its integer type" { fn testBitCastExternEnum() void { var SOCK_DGRAM = @This().B; var sock_dgram = @bitCast(c_int, SOCK_DGRAM); - assert(sock_dgram == 1); + assertOrPanic(sock_dgram == 1); } }; SOCK.testBitCastExternEnum(); comptime SOCK.testBitCastExternEnum(); } - diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig new file mode 100644 index 0000000000..97787ace84 --- /dev/null +++ b/test/stage1/behavior/bitreverse.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const minInt = std.math.minInt; + +test "@bitreverse" { + comptime testBitReverse(); + testBitReverse(); +} + +fn testBitReverse() void { + // using comptime_ints, unsigned + assertOrPanic(@bitreverse(u0, 0) == 0); + assertOrPanic(@bitreverse(u5, 0x12) == 0x9); + assertOrPanic(@bitreverse(u8, 0x12) == 0x48); + assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48); + assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48); + assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using runtime uints, unsigned + var num0: u0 = 0; + assertOrPanic(@bitreverse(u0, num0) == 0); + var num5: u5 = 0x12; + assertOrPanic(@bitreverse(u5, num5) == 0x9); + var num8: u8 = 0x12; + assertOrPanic(@bitreverse(u8, num8) == 0x48); + var num16: u16 = 0x1234; + assertOrPanic(@bitreverse(u16, num16) == 0x2c48); + var num24: u24 = 0x123456; + assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48); + var num32: u32 = 0x12345678; + assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48); + var num40: u40 = 0x123456789a; + assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48); + var num48: u48 = 0x123456789abc; + assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48); + var num56: u56 = 0x123456789abcde; + assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + var num64: u64 = 0x123456789abcdef1; + assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + var num128: u128 = 0x123456789abcdef11121314151617181; + assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using comptime_ints, signed, positive + assertOrPanic(@bitreverse(i0, 0) == 0); + assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); + assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); + assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); + assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); + assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); + assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); + assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); + assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); + assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); + + // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. + var neg5: i5 = minInt(i5) + 1; + assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + var neg8: i8 = -18; + assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + var neg16: i16 = -32694; + assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + var neg24: i24 = -6773785; + assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + var neg32: i32 = -16773785; + assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + var neg40: i40 = minInt(i40) + 12345; + assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + var neg48: i48 = minInt(i48) + 12345; + assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + var neg56: i56 = minInt(i56) + 12345; + assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + var neg64: i64 = minInt(i64) + 12345; + assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + var neg128: i128 = minInt(i128) + 12345; + assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); +} diff --git a/test/cases/bool.zig b/test/stage1/behavior/bool.zig similarity index 50% rename from test/cases/bool.zig rename to test/stage1/behavior/bool.zig index 3e4ac9c1cf..2d7241526f 100644 --- a/test/cases/bool.zig +++ b/test/stage1/behavior/bool.zig @@ -1,25 +1,25 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "bool literals" { - assert(true); - assert(!false); + assertOrPanic(true); + assertOrPanic(!false); } test "cast bool to int" { const t = true; const f = false; - assert(@boolToInt(t) == u32(1)); - assert(@boolToInt(f) == u32(0)); + assertOrPanic(@boolToInt(t) == u32(1)); + assertOrPanic(@boolToInt(f) == u32(0)); nonConstCastBoolToInt(t, f); } fn nonConstCastBoolToInt(t: bool, f: bool) void { - assert(@boolToInt(t) == u32(1)); - assert(@boolToInt(f) == u32(0)); + assertOrPanic(@boolToInt(t) == u32(1)); + assertOrPanic(@boolToInt(f) == u32(0)); } test "bool cmp" { - assert(testBoolCmp(true, false) == false); + assertOrPanic(testBoolCmp(true, false) == false); } fn testBoolCmp(a: bool, b: bool) bool { return a == b; @@ -30,6 +30,6 @@ const global_t = true; const not_global_f = !global_f; const not_global_t = !global_t; test "compile time bool not" { - assert(not_global_f); - assert(!not_global_t); + assertOrPanic(not_global_f); + assertOrPanic(!not_global_t); } diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig new file mode 100644 index 0000000000..8084538e03 --- /dev/null +++ b/test/stage1/behavior/bswap.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "@bswap" { + comptime testByteSwap(); + testByteSwap(); +} + +fn testByteSwap() void { + assertOrPanic(@bswap(u0, 0) == 0); + assertOrPanic(@bswap(u8, 0x12) == 0x12); + assertOrPanic(@bswap(u16, 0x1234) == 0x3412); + assertOrPanic(@bswap(u24, 0x123456) == 0x563412); + assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412); + assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412); + assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + + assertOrPanic(@bswap(i0, 0) == 0); + assertOrPanic(@bswap(i8, -50) == -50); + assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); +} diff --git a/test/cases/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig similarity index 75% rename from test/cases/bugs/1076.zig rename to test/stage1/behavior/bugs/1076.zig index 7b84312310..69a7e70f7d 100644 --- a/test/cases/bugs/1076.zig +++ b/test/stage1/behavior/bugs/1076.zig @@ -1,6 +1,6 @@ const std = @import("std"); const mem = std.mem; -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; test "comptime code should not modify constant data" { testCastPtrOfArrayToSliceAndPtr(); @@ -11,6 +11,6 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assert(mem.eql(u8, array[0..], "boeu")); + assertOrPanic(mem.eql(u8, array[0..], "boeu")); } diff --git a/test/cases/bugs/1111.zig b/test/stage1/behavior/bugs/1111.zig similarity index 100% rename from test/cases/bugs/1111.zig rename to test/stage1/behavior/bugs/1111.zig diff --git a/test/cases/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig similarity index 100% rename from test/cases/bugs/1277.zig rename to test/stage1/behavior/bugs/1277.zig diff --git a/test/cases/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig similarity index 66% rename from test/cases/bugs/1322.zig rename to test/stage1/behavior/bugs/1322.zig index 2de92191ec..2e67f4473f 100644 --- a/test/cases/bugs/1322.zig +++ b/test/stage1/behavior/bugs/1322.zig @@ -13,7 +13,7 @@ const C = struct {}; test "tagged union with all void fields but a meaningful tag" { var a: A = A{ .b = B{ .c = C{} } }; - std.debug.assert(@TagType(B)(a.b) == @TagType(B).c); + std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c); a = A{ .b = B.None }; - std.debug.assert(@TagType(B)(a.b) == @TagType(B).None); + std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None); } diff --git a/test/cases/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig similarity index 100% rename from test/cases/bugs/1381.zig rename to test/stage1/behavior/bugs/1381.zig diff --git a/test/cases/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig similarity index 70% rename from test/cases/bugs/1421.zig rename to test/stage1/behavior/bugs/1421.zig index fcbb8b70e4..fbc932781a 100644 --- a/test/cases/bugs/1421.zig +++ b/test/stage1/behavior/bugs/1421.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const S = struct { fn method() builtin.TypeInfo { @@ -10,5 +10,5 @@ const S = struct { test "functions with return type required to be comptime are generic" { const ti = S.method(); - assert(builtin.TypeId(ti) == builtin.TypeId.Struct); + assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct); } diff --git a/test/cases/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig similarity index 100% rename from test/cases/bugs/1442.zig rename to test/stage1/behavior/bugs/1442.zig diff --git a/test/cases/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig similarity index 51% rename from test/cases/bugs/1486.zig rename to test/stage1/behavior/bugs/1486.zig index 98fae36d3a..0483e3828c 100644 --- a/test/cases/bugs/1486.zig +++ b/test/stage1/behavior/bugs/1486.zig @@ -1,11 +1,11 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const ptr = &global; var global: u64 = 123; test "constant pointer to global variable causes runtime load" { global = 1234; - assert(&global == ptr); - assert(ptr.* == 1234); + assertOrPanic(&global == ptr); + assertOrPanic(ptr.* == 1234); } diff --git a/test/cases/bugs/394.zig b/test/stage1/behavior/bugs/394.zig similarity index 68% rename from test/cases/bugs/394.zig rename to test/stage1/behavior/bugs/394.zig index b0afec2357..766ad9e157 100644 --- a/test/cases/bugs/394.zig +++ b/test/stage1/behavior/bugs/394.zig @@ -7,12 +7,12 @@ const S = struct { y: E, }; -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "bug 394 fixed" { const x = S{ .x = 3, .y = E{ .B = 1 }, }; - assert(x.x == 3); + assertOrPanic(x.x == 3); } diff --git a/test/cases/bugs/655.zig b/test/stage1/behavior/bugs/655.zig similarity index 67% rename from test/cases/bugs/655.zig rename to test/stage1/behavior/bugs/655.zig index ebb8da0658..67ba6a231f 100644 --- a/test/cases/bugs/655.zig +++ b/test/stage1/behavior/bugs/655.zig @@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig"); test "function with *const parameter with type dereferenced by namespace" { const x: other_file.Integer = 1234; - comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer); + comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer); foo(&x); } fn foo(x: *const other_file.Integer) void { - std.debug.assert(x.* == 1234); + std.debug.assertOrPanic(x.* == 1234); } diff --git a/test/cases/bugs/655_other_file.zig b/test/stage1/behavior/bugs/655_other_file.zig similarity index 100% rename from test/cases/bugs/655_other_file.zig rename to test/stage1/behavior/bugs/655_other_file.zig diff --git a/test/cases/bugs/656.zig b/test/stage1/behavior/bugs/656.zig similarity index 84% rename from test/cases/bugs/656.zig rename to test/stage1/behavior/bugs/656.zig index f93f0ac4d5..cb37fe67fe 100644 --- a/test/cases/bugs/656.zig +++ b/test/stage1/behavior/bugs/656.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const PrefixOp = union(enum) { Return, @@ -22,7 +22,7 @@ fn foo(a: bool, b: bool) void { PrefixOp.AddrOf => |addr_of_info| { if (b) {} if (addr_of_info.align_expr) |align_expr| { - assert(align_expr == 1234); + assertOrPanic(align_expr == 1234); } }, PrefixOp.Return => {}, diff --git a/test/cases/bugs/726.zig b/test/stage1/behavior/bugs/726.zig similarity index 71% rename from test/cases/bugs/726.zig rename to test/stage1/behavior/bugs/726.zig index 2acc91eb26..ce20480c63 100644 --- a/test/cases/bugs/726.zig +++ b/test/stage1/behavior/bugs/726.zig @@ -1,9 +1,9 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "@ptrCast from const to nullable" { const c: u8 = 4; var x: ?*const u8 = @ptrCast(?*const u8, &c); - assert(x.?.* == 4); + assertOrPanic(x.?.* == 4); } test "@ptrCast from var in empty struct to nullable" { @@ -11,6 +11,6 @@ test "@ptrCast from var in empty struct to nullable" { var c: u8 = 4; }; var x: ?*const u8 = @ptrCast(?*const u8, &container.c); - assert(x.?.* == 4); + assertOrPanic(x.?.* == 4); } diff --git a/test/cases/bugs/828.zig b/test/stage1/behavior/bugs/828.zig similarity index 100% rename from test/cases/bugs/828.zig rename to test/stage1/behavior/bugs/828.zig diff --git a/test/cases/bugs/920.zig b/test/stage1/behavior/bugs/920.zig similarity index 95% rename from test/cases/bugs/920.zig rename to test/stage1/behavior/bugs/920.zig index 2903f05a29..e29c5c4acf 100644 --- a/test/cases/bugs/920.zig +++ b/test/stage1/behavior/bugs/920.zig @@ -60,6 +60,6 @@ test "bug 920 fixed" { }; for (NormalDist1.f) |_, i| { - std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]); + std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]); } } diff --git a/test/cases/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig similarity index 70% rename from test/cases/byval_arg_var.zig rename to test/stage1/behavior/byval_arg_var.zig index 826b9cc9e5..14ee212ce0 100644 --- a/test/cases/byval_arg_var.zig +++ b/test/stage1/behavior/byval_arg_var.zig @@ -2,11 +2,11 @@ const std = @import("std"); var result: []const u8 = "wrong"; -test "aoeu" { +test "pass string literal byvalue to a generic var param" { start(); blowUpStack(10); - std.debug.assert(std.mem.eql(u8, result, "string literal")); + std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal")); } fn start() void { diff --git a/test/cases/cancel.zig b/test/stage1/behavior/cancel.zig similarity index 84% rename from test/cases/cancel.zig rename to test/stage1/behavior/cancel.zig index c0f74fd34f..863da4bdb8 100644 --- a/test/cases/cancel.zig +++ b/test/stage1/behavior/cancel.zig @@ -10,9 +10,9 @@ test "cancel forwards" { const p = async<&da.allocator> f1() catch unreachable; cancel p; - std.debug.assert(defer_f1); - std.debug.assert(defer_f2); - std.debug.assert(defer_f3); + std.debug.assertOrPanic(defer_f1); + std.debug.assertOrPanic(defer_f2); + std.debug.assertOrPanic(defer_f3); } async fn f1() void { @@ -47,10 +47,10 @@ test "cancel backwards" { const p = async<&da.allocator> b1() catch unreachable; cancel p; - std.debug.assert(defer_b1); - std.debug.assert(defer_b2); - std.debug.assert(defer_b3); - std.debug.assert(defer_b4); + std.debug.assertOrPanic(defer_b1); + std.debug.assertOrPanic(defer_b2); + std.debug.assertOrPanic(defer_b3); + std.debug.assertOrPanic(defer_b4); } async fn b1() void { diff --git a/test/cases/cast.zig b/test/stage1/behavior/cast.zig similarity index 67% rename from test/cases/cast.zig rename to test/stage1/behavior/cast.zig index bd45bbc00f..61ddcd8135 100644 --- a/test/cases/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const mem = std.mem; const maxInt = std.math.maxInt; @@ -7,12 +7,12 @@ test "int to ptr cast" { const x = usize(13); const y = @intToPtr(*u8, x); const z = @ptrToInt(y); - assert(z == 13); + assertOrPanic(z == 13); } test "integer literal to pointer cast" { const vga_mem = @intToPtr(*u16, 0xB8000); - assert(@ptrToInt(vga_mem) == 0xB8000); + assertOrPanic(@ptrToInt(vga_mem) == 0xB8000); } test "pointer reinterpret const float to int" { @@ -20,7 +20,7 @@ test "pointer reinterpret const float to int" { const float_ptr = &float; const int_ptr = @ptrCast(*const i32, float_ptr); const int_val = int_ptr.*; - assert(int_val == 858993411); + assertOrPanic(int_val == 858993411); } test "implicitly cast indirect pointer to maybe-indirect pointer" { @@ -44,10 +44,10 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" { const p = &s; const q = &p; const r = &q; - assert(42 == S.constConst(q)); - assert(42 == S.maybeConstConst(q)); - assert(42 == S.constConstConst(r)); - assert(42 == S.maybeConstConstConst(r)); + assertOrPanic(42 == S.constConst(q)); + assertOrPanic(42 == S.maybeConstConst(q)); + assertOrPanic(42 == S.constConstConst(r)); + assertOrPanic(42 == S.maybeConstConstConst(r)); } test "explicit cast from integer to error type" { @@ -57,14 +57,14 @@ test "explicit cast from integer to error type" { fn testCastIntToErr(err: anyerror) void { const x = @errorToInt(err); const y = @intToError(x); - assert(error.ItBroke == y); + assertOrPanic(error.ItBroke == y); } test "peer resolve arrays of different size to const slice" { - assert(mem.eql(u8, boolToStr(true), "true")); - assert(mem.eql(u8, boolToStr(false), "false")); - comptime assert(mem.eql(u8, boolToStr(true), "true")); - comptime assert(mem.eql(u8, boolToStr(false), "false")); + assertOrPanic(mem.eql(u8, boolToStr(true), "true")); + assertOrPanic(mem.eql(u8, boolToStr(false), "false")); + comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true")); + comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false")); } fn boolToStr(b: bool) []const u8 { return if (b) "true" else "false"; @@ -77,28 +77,29 @@ test "peer resolve array and const slice" { fn testPeerResolveArrayConstSlice(b: bool) void { const value1 = if (b) "aoeu" else ([]const u8)("zz"); const value2 = if (b) ([]const u8)("zz") else "aoeu"; - assert(mem.eql(u8, value1, "aoeu")); - assert(mem.eql(u8, value2, "zz")); + assertOrPanic(mem.eql(u8, value1, "aoeu")); + assertOrPanic(mem.eql(u8, value2, "zz")); } test "implicitly cast from T to anyerror!?T" { castToOptionalTypeError(1); comptime castToOptionalTypeError(1); } + const A = struct { a: i32, }; fn castToOptionalTypeError(z: i32) void { const x = i32(1); const y: anyerror!?i32 = x; - assert((try y).? == 1); + assertOrPanic((try y).? == 1); const f = z; const g: anyerror!?i32 = f; const a = A{ .a = z }; const b: anyerror!?A = a; - assert((b catch unreachable).?.a == 1); + assertOrPanic((b catch unreachable).?.a == 1); } test "implicitly cast from int to anyerror!?T" { @@ -113,7 +114,7 @@ fn implicitIntLitToOptional() void { test "return null from fn() anyerror!?&T" { const a = returnNullFromOptionalTypeErrorRef(); const b = returnNullLitFromOptionalTypeErrorRef(); - assert((try a) == null and (try b) == null); + assertOrPanic((try a) == null and (try b) == null); } fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { const a: ?*A = null; @@ -124,11 +125,11 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { } test "peer type resolution: ?T and T" { - assert(peerTypeTAndOptionalT(true, false).? == 0); - assert(peerTypeTAndOptionalT(false, false).? == 3); + assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); + assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); comptime { - assert(peerTypeTAndOptionalT(true, false).? == 0); - assert(peerTypeTAndOptionalT(false, false).? == 3); + assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); + assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); } } fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { @@ -140,11 +141,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { } test "peer type resolution: [0]u8 and []const u8" { - assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); comptime { - assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); } } fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { @@ -156,8 +157,8 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { } test "implicitly cast from [N]T to ?[]const T" { - assert(mem.eql(u8, castToOptionalSlice().?, "hi")); - comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi")); + assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); + comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); } fn castToOptionalSlice() ?[]const u8 { @@ -170,7 +171,7 @@ test "implicitly cast from [0]T to anyerror![]T" { } fn testCastZeroArrayToErrSliceMut() void { - assert((gimmeErrOrSlice() catch unreachable).len == 0); + assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0); } fn gimmeErrOrSlice() anyerror![]u8 { @@ -181,14 +182,14 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { { var data = "hi"; const slice = data[0..]; - assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } comptime { var data = "hi"; const slice = data[0..]; - assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } } fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { @@ -206,7 +207,7 @@ test "resolve undefined with integer" { fn testResolveUndefWithInt(b: bool, x: i32) void { const value = if (b) x else undefined; if (b) { - assert(value == x); + assertOrPanic(value == x); } } @@ -218,17 +219,17 @@ test "implicit cast from &const [N]T to []const T" { fn testCastConstArrayRefToConstSlice() void { const blah = "aoeu"; const const_array_ref = &blah; - assert(@typeOf(const_array_ref) == *const [4]u8); + assertOrPanic(@typeOf(const_array_ref) == *const [4]u8); const slice: []const u8 = const_array_ref; - assert(mem.eql(u8, slice, "aoeu")); + assertOrPanic(mem.eql(u8, slice, "aoeu")); } test "peer type resolution: error and [N]T" { // TODO: implicit error!T to error!U where T can implicitly cast to U - //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); - comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); } //fn testPeerErrorAndArray(x: u8) error![]const u8 { @@ -252,9 +253,9 @@ test "@floatToInt" { fn testFloatToInts() void { const x = i32(1e4); - assert(x == 10000); + assertOrPanic(x == 10000); const y = @floatToInt(i32, f32(1e4)); - assert(y == 10000); + assertOrPanic(y == 10000); expectFloatToInt(f16, 255.1, u8, 255); expectFloatToInt(f16, 127.2, i8, 127); expectFloatToInt(f16, -128.2, i8, -128); @@ -265,7 +266,7 @@ fn testFloatToInts() void { } fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { - assert(@floatToInt(I, f) == i); + assertOrPanic(@floatToInt(I, f) == i); } test "cast u128 to f128 and back" { @@ -274,7 +275,7 @@ test "cast u128 to f128 and back" { } fn testCast128() void { - assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); + assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); } fn cast128Int(x: f128) u128 { @@ -294,9 +295,9 @@ test "const slice widen cast" { }; const u32_value = @bytesToSlice(u32, bytes[0..])[0]; - assert(u32_value == 0x12121212); + assertOrPanic(u32_value == 0x12121212); - assert(@bitCast(u32, bytes) == 0x12121212); + assertOrPanic(@bitCast(u32, bytes) == 0x12121212); } test "single-item pointer of array to slice and to unknown length pointer" { @@ -308,76 +309,76 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assert(mem.eql(u8, array[0..], "boeu")); + assertOrPanic(mem.eql(u8, array[0..], "boeu")); const y: []u8 = &array; y[0] += 1; - assert(mem.eql(u8, array[0..], "coeu")); + assertOrPanic(mem.eql(u8, array[0..], "coeu")); } test "cast *[1][*]const u8 to [*]const ?[*]const u8" { const window_name = [1][*]const u8{c"window name"}; const x: [*]const ?[*]const u8 = &window_name; - assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); + assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); } test "@intCast comptime_int" { const result = @intCast(i32, 1234); - assert(@typeOf(result) == i32); - assert(result == 1234); + assertOrPanic(@typeOf(result) == i32); + assertOrPanic(result == 1234); } test "@floatCast comptime_int and comptime_float" { { const result = @floatCast(f16, 1234); - assert(@typeOf(result) == f16); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); } { const result = @floatCast(f16, 1234.0); - assert(@typeOf(result) == f16); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); } { const result = @floatCast(f32, 1234); - assert(@typeOf(result) == f32); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); } { const result = @floatCast(f32, 1234.0); - assert(@typeOf(result) == f32); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); } } test "comptime_int @intToFloat" { { const result = @intToFloat(f16, 1234); - assert(@typeOf(result) == f16); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); } { const result = @intToFloat(f32, 1234); - assert(@typeOf(result) == f32); - assert(result == 1234.0); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); } } test "@bytesToSlice keeps pointer alignment" { var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; const numbers = @bytesToSlice(u32, bytes[0..]); - comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); + comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); } test "@intCast i32 to u7" { var x: u128 = maxInt(u128); var y: i32 = 120; var z = x >> @intCast(u7, y); - assert(z == 0xff); + assertOrPanic(z == 0xff); } test "implicit cast undefined to optional" { - assert(MakeType(void).getNull() == null); - assert(MakeType(void).getNonNull() != null); + assertOrPanic(MakeType(void).getNull() == null); + assertOrPanic(MakeType(void).getNonNull() != null); } fn MakeType(comptime T: type) type { @@ -397,16 +398,16 @@ test "implicit cast from *[N]T to ?[*]T" { var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; x = &y; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); + assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); x.?[0] = 8; y[3] = 6; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); + assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); } test "implicit cast from *T to ?*c_void" { var a: u8 = 1; incrementVoidPtrValue(&a); - std.debug.assert(a == 2); + std.debug.assertOrPanic(a == 2); } fn incrementVoidPtrValue(value: ?*c_void) void { @@ -416,7 +417,7 @@ fn incrementVoidPtrValue(value: ?*c_void) void { test "implicit cast from [*]T to ?*c_void" { var a = []u8{ 3, 2, 1 }; incrementVoidPtrArray(a[0..].ptr, 3); - assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); + assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); } fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { @@ -440,27 +441,27 @@ pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); pub const PFN_void = extern fn (*c_void) void; fn foobar(func: PFN_void) void { - std.debug.assert(@ptrToInt(func) == maxInt(usize)); + std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize)); } test "implicit ptr to *c_void" { var a: u32 = 1; var ptr: *c_void = &a; var b: *u32 = @ptrCast(*u32, ptr); - assert(b.* == 1); + assertOrPanic(b.* == 1); var ptr2: ?*c_void = &a; var c: *u32 = @ptrCast(*u32, ptr2.?); - assert(c.* == 1); + assertOrPanic(c.* == 1); } test "@intCast to comptime_int" { - assert(@intCast(comptime_int, 0) == 0); + assertOrPanic(@intCast(comptime_int, 0) == 0); } test "implicit cast comptime numbers to any type when the value fits" { const a: u64 = 255; var b: u8 = a; - assert(b == 255); + assertOrPanic(b == 255); } test "@intToEnum passed a comptime_int to an enum with one item" { @@ -468,5 +469,5 @@ test "@intToEnum passed a comptime_int to an enum with one item" { A, }; const x = @intToEnum(E, 0); - assert(x == E.A); + assertOrPanic(x == E.A); } diff --git a/test/cases/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig similarity index 80% rename from test/cases/const_slice_child.zig rename to test/stage1/behavior/const_slice_child.zig index 07d02d5df0..5b9b70a558 100644 --- a/test/cases/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -1,5 +1,5 @@ const debug = @import("std").debug; -const assert = debug.assert; +const assertOrPanic = debug.assertOrPanic; var argv: [*]const [*]const u8 = undefined; @@ -15,10 +15,10 @@ test "const slice child" { } fn foo(args: [][]const u8) void { - assert(args.len == 3); - assert(streql(args[0], "one")); - assert(streql(args[1], "two")); - assert(streql(args[2], "three")); + assertOrPanic(args.len == 3); + assertOrPanic(streql(args[0], "one")); + assertOrPanic(streql(args[1], "two")); + assertOrPanic(streql(args[2], "three")); } fn bar(argc: usize) void { diff --git a/test/cases/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig similarity index 86% rename from test/cases/coroutine_await_struct.zig rename to test/stage1/behavior/coroutine_await_struct.zig index 79168715d8..6ca2a301ec 100644 --- a/test/cases/coroutine_await_struct.zig +++ b/test/stage1/behavior/coroutine_await_struct.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const Foo = struct { x: i32, @@ -18,8 +18,8 @@ test "coroutine await struct" { await_seq('f'); resume await_a_promise; await_seq('i'); - assert(await_final_result.x == 1234); - assert(std.mem.eql(u8, await_points, "abcdefghi")); + assertOrPanic(await_final_result.x == 1234); + assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); diff --git a/test/cases/coroutines.zig b/test/stage1/behavior/coroutines.zig similarity index 86% rename from test/cases/coroutines.zig rename to test/stage1/behavior/coroutines.zig index 89490ebc2c..a2327c5060 100644 --- a/test/cases/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; var x: i32 = 1; @@ -9,9 +9,9 @@ test "create a coroutine and cancel it" { defer da.deinit(); const p = try async<&da.allocator> simpleAsyncFn(); - comptime assert(@typeOf(p) == promise->void); + comptime assertOrPanic(@typeOf(p) == promise->void); cancel p; - assert(x == 2); + assertOrPanic(x == 2); } async fn simpleAsyncFn() void { x += 1; @@ -31,7 +31,7 @@ test "coroutine suspend, resume, cancel" { cancel p; seq('g'); - assert(std.mem.eql(u8, points, "abcdefg")); + assertOrPanic(std.mem.eql(u8, points, "abcdefg")); } async fn testAsyncSeq() void { defer seq('e'); @@ -53,9 +53,9 @@ test "coroutine suspend with block" { defer da.deinit(); const p = try async<&da.allocator> testSuspendBlock(); - std.debug.assert(!result); + std.debug.assertOrPanic(!result); resume a_promise; - std.debug.assert(result); + std.debug.assertOrPanic(result); cancel p; } @@ -63,13 +63,13 @@ var a_promise: promise = undefined; var result = false; async fn testSuspendBlock() void { suspend { - comptime assert(@typeOf(@handle()) == promise->void); + comptime assertOrPanic(@typeOf(@handle()) == promise->void); a_promise = @handle(); } //Test to make sure that @handle() works as advertised (issue #1296) //var our_handle: promise = @handle(); - assert( a_promise == @handle() ); + assertOrPanic(a_promise == @handle()); result = true; } @@ -86,8 +86,8 @@ test "coroutine await" { await_seq('f'); resume await_a_promise; await_seq('i'); - assert(await_final_result == 1234); - assert(std.mem.eql(u8, await_points, "abcdefghi")); + assertOrPanic(await_final_result == 1234); + assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); @@ -123,8 +123,8 @@ test "coroutine await early return" { early_seq('a'); const p = async<&da.allocator> early_amain() catch @panic("out of memory"); early_seq('f'); - assert(early_final_result == 1234); - assert(std.mem.eql(u8, early_points, "abcdef")); + assertOrPanic(early_final_result == 1234); + assertOrPanic(std.mem.eql(u8, early_points, "abcdef")); } async fn early_amain() void { early_seq('b'); @@ -170,7 +170,7 @@ test "async function with dot syntax" { defer da.deinit(); const p = try async<&da.allocator> S.foo(); cancel p; - assert(S.y == 2); + assertOrPanic(S.y == 2); } test "async fn pointer in a struct field" { @@ -182,9 +182,9 @@ test "async fn pointer in a struct field" { var da = std.heap.DirectAllocator.init(); defer da.deinit(); const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; - assert(data == 2); + assertOrPanic(data == 2); cancel p; - assert(data == 4); + assertOrPanic(data == 4); } async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { defer y.* += 2; @@ -199,6 +199,7 @@ test "async fn with inferred error set" { resume p; cancel p; } + async fn failing() !void { suspend; return error.Fail; @@ -220,8 +221,7 @@ test "error return trace across suspend points - async return" { cancel p2; } -// TODO https://github.com/ziglang/zig/issues/760 -fn nonFailing() promise->(anyerror!void) { +fn nonFailing() (promise->anyerror!void) { return async suspendThenFail() catch unreachable; } async fn suspendThenFail() anyerror!void { @@ -230,9 +230,9 @@ async fn suspendThenFail() anyerror!void { } async fn printTrace(p: promise->(anyerror!void)) void { (await p) catch |e| { - std.debug.assert(e == error.Fail); + std.debug.assertOrPanic(e == error.Fail); if (@errorReturnTrace()) |trace| { - assert(trace.index == 1); + assertOrPanic(trace.index == 1); } else switch (builtin.mode) { builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, @@ -246,7 +246,7 @@ test "break from suspend" { var my_result: i32 = 1; const p = try async testBreakFromSuspend(&my_result); cancel p; - std.debug.assert(my_result == 2); + std.debug.assertOrPanic(my_result == 2); } async fn testBreakFromSuspend(my_result: *i32) void { suspend { diff --git a/test/cases/defer.zig b/test/stage1/behavior/defer.zig similarity index 72% rename from test/cases/defer.zig rename to test/stage1/behavior/defer.zig index f9a2b69cd9..6c6c60311e 100644 --- a/test/cases/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; var result: [3]u8 = undefined; var index: usize = undefined; @@ -21,18 +21,18 @@ fn runSomeErrorDefers(x: bool) !bool { } test "mixing normal and error defers" { - assert(runSomeErrorDefers(true) catch unreachable); - assert(result[0] == 'c'); - assert(result[1] == 'a'); + assertOrPanic(runSomeErrorDefers(true) catch unreachable); + assertOrPanic(result[0] == 'c'); + assertOrPanic(result[1] == 'a'); const ok = runSomeErrorDefers(false) catch |err| x: { - assert(err == error.FalseNotAllowed); + assertOrPanic(err == error.FalseNotAllowed); break :x true; }; - assert(ok); - assert(result[0] == 'c'); - assert(result[1] == 'b'); - assert(result[2] == 'a'); + assertOrPanic(ok); + assertOrPanic(result[0] == 'c'); + assertOrPanic(result[1] == 'b'); + assertOrPanic(result[2] == 'a'); } test "break and continue inside loop inside defer expression" { @@ -47,7 +47,7 @@ fn testBreakContInDefer(x: usize) void { if (i < 5) continue; if (i == 5) break; } - assert(i == 5); + assertOrPanic(i == 5); } } @@ -59,11 +59,11 @@ test "defer and labeled break" { break :blk; } - assert(i == 1); + assertOrPanic(i == 1); } test "errdefer does not apply to fn inside fn" { - if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad); + if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad); } fn testNestedFnErrDefer() anyerror!void { diff --git a/test/cases/enum.zig b/test/stage1/behavior/enum.zig similarity index 84% rename from test/cases/enum.zig rename to test/stage1/behavior/enum.zig index 2dd552488c..9de138ef78 100644 --- a/test/cases/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const mem = @import("std").mem; test "enum type" { @@ -11,16 +11,16 @@ test "enum type" { }; const bar = Bar.B; - assert(bar == Bar.B); - assert(@memberCount(Foo) == 3); - assert(@memberCount(Bar) == 4); - assert(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - assert(@sizeOf(Bar) == 1); + assertOrPanic(bar == Bar.B); + assertOrPanic(@memberCount(Foo) == 3); + assertOrPanic(@memberCount(Bar) == 4); + assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + assertOrPanic(@sizeOf(Bar) == 1); } test "enum as return value" { switch (returnAnInt(13)) { - Foo.One => |value| assert(value == 13), + Foo.One => |value| assertOrPanic(value == 13), else => unreachable, } } @@ -92,14 +92,14 @@ test "enum to int" { } fn shouldEqual(n: Number, expected: u3) void { - assert(@enumToInt(n) == expected); + assertOrPanic(@enumToInt(n) == expected); } test "int to enum" { testIntToEnumEval(3); } fn testIntToEnumEval(x: i32) void { - assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); + assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); } const IntToEnumNumber = enum { Zero, @@ -110,8 +110,8 @@ const IntToEnumNumber = enum { }; test "@tagName" { - assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); - comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); } fn testEnumTagNameBare(n: BareNumber) []const u8 { @@ -126,8 +126,8 @@ const BareNumber = enum { test "enum alignment" { comptime { - assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); - assert(@alignOf(AlignTestEnum) >= @alignOf(u64)); + assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); + assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64)); } } @@ -663,10 +663,10 @@ const ValueCount257 = enum { test "enum sizes" { comptime { - assert(@sizeOf(ValueCount1) == 0); - assert(@sizeOf(ValueCount2) == 1); - assert(@sizeOf(ValueCount256) == 1); - assert(@sizeOf(ValueCount257) == 2); + assertOrPanic(@sizeOf(ValueCount1) == 0); + assertOrPanic(@sizeOf(ValueCount2) == 1); + assertOrPanic(@sizeOf(ValueCount256) == 1); + assertOrPanic(@sizeOf(ValueCount257) == 2); } } @@ -685,12 +685,12 @@ test "set enum tag type" { { var x = Small.One; x = Small.Two; - comptime assert(@TagType(Small) == u2); + comptime assertOrPanic(@TagType(Small) == u2); } { var x = Small2.One; x = Small2.Two; - comptime assert(@TagType(Small2) == u2); + comptime assertOrPanic(@TagType(Small2) == u2); } } @@ -737,17 +737,17 @@ const bit_field_1 = BitFieldOfEnums{ test "bit field access with enum fields" { var data = bit_field_1; - assert(getA(&data) == A.Two); - assert(getB(&data) == B.Three3); - assert(getC(&data) == C.Four4); - comptime assert(@sizeOf(BitFieldOfEnums) == 1); + assertOrPanic(getA(&data) == A.Two); + assertOrPanic(getB(&data) == B.Three3); + assertOrPanic(getC(&data) == C.Four4); + comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1); data.b = B.Four3; - assert(data.b == B.Four3); + assertOrPanic(data.b == B.Four3); data.a = A.Three; - assert(data.a == A.Three); - assert(data.b == B.Four3); + assertOrPanic(data.a == A.Three); + assertOrPanic(data.b == B.Four3); } fn getA(data: *const BitFieldOfEnums) A { @@ -768,7 +768,7 @@ test "casting enum to its tag type" { } fn testCastEnumToTagType(value: Small2) void { - assert(@enumToInt(value) == 1); + assertOrPanic(@enumToInt(value) == 1); } const MultipleChoice = enum(u32) { @@ -784,8 +784,8 @@ test "enum with specified tag values" { } fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { - assert(@enumToInt(x) == 60); - assert(1234 == switch (x) { + assertOrPanic(@enumToInt(x) == 60); + assertOrPanic(1234 == switch (x) { MultipleChoice.A => 1, MultipleChoice.B => 2, MultipleChoice.C => u32(1234), @@ -811,8 +811,8 @@ test "enum with specified and unspecified tag values" { } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assert(@enumToInt(x) == 1000); - assert(1234 == switch (x) { + assertOrPanic(@enumToInt(x) == 1000); + assertOrPanic(1234 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => 3, @@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { } test "cast integer literal to enum" { - assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); - assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); + assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); + assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); } const EnumWithOneMember = enum { @@ -865,14 +865,14 @@ const EnumWithTagValues = enum(u4) { D = 1 << 3, }; test "enum with tag values don't require parens" { - assert(@enumToInt(EnumWithTagValues.C) == 0b0100); + assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100); } test "enum with 1 field but explicit tag type should still have the tag type" { const Enum = enum(u8) { B = 2, }; - comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8)); + comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8)); } test "empty extern enum with members" { @@ -881,14 +881,14 @@ test "empty extern enum with members" { B, C, }; - assert(@sizeOf(E) == @sizeOf(c_int)); + assertOrPanic(@sizeOf(E) == @sizeOf(c_int)); } -test "aoeu" { +test "tag name with assigned enum values" { const LocalFoo = enum { A = 1, B = 0, }; var b = LocalFoo.B; - assert(mem.eql(u8, @tagName(b), "B")); + assertOrPanic(mem.eql(u8, @tagName(b), "B")); } diff --git a/test/cases/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig similarity index 63% rename from test/cases/enum_with_members.zig rename to test/stage1/behavior/enum_with_members.zig index 088496bd2f..49af1ceae7 100644 --- a/test/cases/enum_with_members.zig +++ b/test/stage1/behavior/enum_with_members.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const mem = @import("std").mem; const fmt = @import("std").fmt; @@ -19,9 +19,9 @@ test "enum with members" { const b = ET{ .UINT = 42 }; var buf: [20]u8 = undefined; - assert((a.print(buf[0..]) catch unreachable) == 3); - assert(mem.eql(u8, buf[0..3], "-42")); + assertOrPanic((a.print(buf[0..]) catch unreachable) == 3); + assertOrPanic(mem.eql(u8, buf[0..3], "-42")); - assert((b.print(buf[0..]) catch unreachable) == 2); - assert(mem.eql(u8, buf[0..2], "42")); + assertOrPanic((b.print(buf[0..]) catch unreachable) == 2); + assertOrPanic(mem.eql(u8, buf[0..2], "42")); } diff --git a/test/cases/error.zig b/test/stage1/behavior/error.zig similarity index 58% rename from test/cases/error.zig rename to test/stage1/behavior/error.zig index a731f39021..c7e38712bc 100644 --- a/test/cases/error.zig +++ b/test/stage1/behavior/error.zig @@ -1,5 +1,6 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; +const assertError = std.debug.assertError; const mem = std.mem; const builtin = @import("builtin"); @@ -18,7 +19,7 @@ pub fn baz() anyerror!i32 { } test "error wrapping" { - assert((baz() catch unreachable) == 15); + assertOrPanic((baz() catch unreachable) == 15); } fn gimmeItBroke() []const u8 { @@ -26,14 +27,14 @@ fn gimmeItBroke() []const u8 { } test "@errorName" { - assert(mem.eql(u8, @errorName(error.AnError), "AnError")); - assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); + assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError")); + assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); } test "error values" { const a = @errorToInt(error.err1); const b = @errorToInt(error.err2); - assert(a != b); + assertOrPanic(a != b); } test "redefinition of error values allowed" { @@ -46,8 +47,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { test "error binary operator" { const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; - assert(a == 3); - assert(b == 10); + assertOrPanic(a == 3); + assertOrPanic(b == 10); } fn errBinaryOperatorG(x: bool) anyerror!isize { return if (x) error.ItBroke else isize(10); @@ -55,7 +56,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize { test "unwrap simple value from error" { const i = unwrapSimpleValueFromErrorDo() catch unreachable; - assert(i == 13); + assertOrPanic(i == 13); } fn unwrapSimpleValueFromErrorDo() anyerror!isize { return 13; @@ -81,13 +82,13 @@ test "error union type " { fn testErrorUnionType() void { const x: anyerror!i32 = 1234; - if (x) |value| assert(value == 1234) else |_| unreachable; - assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); - assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); - assert(@typeOf(x).ErrorSet == anyerror); + if (x) |value| assertOrPanic(value == 1234) else |_| unreachable; + assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); + assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); + assertOrPanic(@typeOf(x).ErrorSet == anyerror); } -test "error set type " { +test "error set type" { testErrorSetType(); comptime testErrorSetType(); } @@ -98,12 +99,12 @@ const MyErrSet = error{ }; fn testErrorSetType() void { - assert(@memberCount(MyErrSet) == 2); + assertOrPanic(@memberCount(MyErrSet) == 2); const a: MyErrSet!i32 = 5678; const b: MyErrSet!i32 = MyErrSet.OutOfMemory; - if (a) |value| assert(value == 5678) else |err| switch (err) { + if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) { error.OutOfMemory => unreachable, error.FileNotFound => unreachable, } @@ -126,7 +127,7 @@ const Set2 = error{ fn testExplicitErrorSetCast(set1: Set1) void { var x = @errSetCast(Set2, set1); var y = @errSetCast(Set1, x); - assert(y == error.A); + assertOrPanic(y == error.A); } test "comptime test error for empty error set" { @@ -137,12 +138,12 @@ test "comptime test error for empty error set" { const EmptyErrorSet = error{}; fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { - if (x) |v| assert(v == 1234) else |err| @compileError("bad"); + if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad"); } test "syntax: optional operator in front of error union operator" { comptime { - assert(?(anyerror!i32) == ?(anyerror!i32)); + assertOrPanic(?(anyerror!i32) == ?(anyerror!i32)); } } @@ -161,7 +162,6 @@ fn testErrToIntWithOnePossibleValue( test "error union peer type resolution" { testErrorUnionPeerTypeResolution(1); - comptime testErrorUnionPeerTypeResolution(1); } fn testErrorUnionPeerTypeResolution(x: i32) void { @@ -170,6 +170,11 @@ fn testErrorUnionPeerTypeResolution(x: i32) void { 2 => baz_1(), else => quux_1(), }; + if (y) |_| { + @panic("expected error"); + } else |e| { + assertOrPanic(e == error.A); + } } fn bar_1() anyerror { @@ -243,3 +248,85 @@ fn intLiteral(str: []const u8) !?i64 { return error.T; } + +test "nested error union function call in optional unwrap" { + const S = struct { + const Foo = struct { + a: i32, + }; + + fn errorable() !i32 { + var x: Foo = (try getFoo()) orelse return error.Other; + return x.a; + } + + fn errorable2() !i32 { + var x: Foo = (try getFoo2()) orelse return error.Other; + return x.a; + } + + fn errorable3() !i32 { + var x: Foo = (try getFoo3()) orelse return error.Other; + return x.a; + } + + fn getFoo() anyerror!?Foo { + return Foo{ .a = 1234 }; + } + + fn getFoo2() anyerror!?Foo { + return error.Failure; + } + + fn getFoo3() anyerror!?Foo { + return null; + } + }; + assertOrPanic((try S.errorable()) == 1234); + assertError(S.errorable2(), error.Failure); + assertError(S.errorable3(), error.Other); + comptime { + assertOrPanic((try S.errorable()) == 1234); + assertError(S.errorable2(), error.Failure); + assertError(S.errorable3(), error.Other); + } +} + +test "widen cast integer payload of error union function call" { + const S = struct { + fn errorable() !u64 { + var x = u64(try number()); + return x; + } + + fn number() anyerror!u32 { + return 1234; + } + }; + assertOrPanic((try S.errorable()) == 1234); +} + +test "return function call to error set from error union function" { + const S = struct { + fn errorable() anyerror!i32 { + return fail(); + } + + fn fail() anyerror { + return error.Failure; + } + }; + assertError(S.errorable(), error.Failure); + comptime assertError(S.errorable(), error.Failure); +} + +test "optional error set is the same size as error set" { + comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror)); + const S = struct { + fn returnsOptErrSet() ?anyerror { + return null; + } + }; + assertOrPanic(S.returnsOptErrSet() == null); + comptime assertOrPanic(S.returnsOptErrSet() == null); +} diff --git a/test/cases/eval.zig b/test/stage1/behavior/eval.zig similarity index 70% rename from test/cases/eval.zig rename to test/stage1/behavior/eval.zig index a9eded151e..2d8494eb0b 100644 --- a/test/cases/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const builtin = @import("builtin"); test "compile time recursion" { - assert(some_data.len == 21); + assertOrPanic(some_data.len == 21); } var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; fn fibonacci(x: i32) i32 { @@ -16,7 +16,7 @@ fn unwrapAndAddOne(blah: ?i32) i32 { } const should_be_1235 = unwrapAndAddOne(1234); test "static add one" { - assert(should_be_1235 == 1235); + assertOrPanic(should_be_1235 == 1235); } test "inlined loop" { @@ -24,7 +24,7 @@ test "inlined loop" { comptime var sum = 0; inline while (i <= 5) : (i += 1) sum += i; - assert(sum == 15); + assertOrPanic(sum == 15); } fn gimme1or2(comptime a: bool) i32 { @@ -34,12 +34,12 @@ fn gimme1or2(comptime a: bool) i32 { return z; } test "inline variable gets result of const if" { - assert(gimme1or2(true) == 1); - assert(gimme1or2(false) == 2); + assertOrPanic(gimme1or2(true) == 1); + assertOrPanic(gimme1or2(false) == 2); } test "static function evaluation" { - assert(statically_added_number == 3); + assertOrPanic(statically_added_number == 3); } const statically_added_number = staticAdd(1, 2); fn staticAdd(a: i32, b: i32) i32 { @@ -47,7 +47,8 @@ fn staticAdd(a: i32, b: i32) i32 { } test "const expr eval on single expr blocks" { - assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); } fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { @@ -63,10 +64,10 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { } test "statically initialized list" { - assert(static_point_list[0].x == 1); - assert(static_point_list[0].y == 2); - assert(static_point_list[1].x == 3); - assert(static_point_list[1].y == 4); + assertOrPanic(static_point_list[0].x == 1); + assertOrPanic(static_point_list[0].y == 2); + assertOrPanic(static_point_list[1].x == 3); + assertOrPanic(static_point_list[1].y == 4); } const Point = struct { x: i32, @@ -84,8 +85,8 @@ fn makePoint(x: i32, y: i32) Point { } test "static eval list init" { - assert(static_vec3.data[2] == 1.0); - assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0); + assertOrPanic(static_vec3.data[2] == 1.0); + assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0); } const static_vec3 = vec3(0.0, 0.0, 1.0); pub const Vec3 = struct { @@ -101,12 +102,12 @@ pub fn vec3(x: f32, y: f32, z: f32) Vec3 { test "constant expressions" { var array: [array_size]u8 = undefined; - assert(@sizeOf(@typeOf(array)) == 20); + assertOrPanic(@sizeOf(@typeOf(array)) == 20); } const array_size: u8 = 20; test "constant struct with negation" { - assert(vertices[0].x == -0.6); + assertOrPanic(vertices[0].x == -0.6); } const Vertex = struct { x: f32, @@ -141,7 +142,7 @@ const vertices = []Vertex{ test "statically initialized struct" { st_init_str_foo.x += 1; - assert(st_init_str_foo.x == 14); + assertOrPanic(st_init_str_foo.x == 14); } const StInitStrFoo = struct { x: i32, @@ -154,7 +155,7 @@ var st_init_str_foo = StInitStrFoo{ test "statically initalized array literal" { const y: [4]u8 = st_init_arr_lit_x; - assert(y[3] == 4); + assertOrPanic(y[3] == 4); } const st_init_arr_lit_x = []u8{ 1, @@ -166,15 +167,15 @@ const st_init_arr_lit_x = []u8{ test "const slice" { comptime { const a = "1234567890"; - assert(a.len == 10); + assertOrPanic(a.len == 10); const b = a[1..2]; - assert(b.len == 1); - assert(b[0] == '2'); + assertOrPanic(b.len == 1); + assertOrPanic(b[0] == '2'); } } test "try to trick eval with runtime if" { - assert(testTryToTrickEvalWithRuntimeIf(true) == 10); + assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10); } fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { @@ -200,16 +201,16 @@ fn letsTryToCompareBools(a: bool, b: bool) bool { return max(bool, a, b); } test "inlined block and runtime block phi" { - assert(letsTryToCompareBools(true, true)); - assert(letsTryToCompareBools(true, false)); - assert(letsTryToCompareBools(false, true)); - assert(!letsTryToCompareBools(false, false)); + assertOrPanic(letsTryToCompareBools(true, true)); + assertOrPanic(letsTryToCompareBools(true, false)); + assertOrPanic(letsTryToCompareBools(false, true)); + assertOrPanic(!letsTryToCompareBools(false, false)); comptime { - assert(letsTryToCompareBools(true, true)); - assert(letsTryToCompareBools(true, false)); - assert(letsTryToCompareBools(false, true)); - assert(!letsTryToCompareBools(false, false)); + assertOrPanic(letsTryToCompareBools(true, true)); + assertOrPanic(letsTryToCompareBools(true, false)); + assertOrPanic(letsTryToCompareBools(false, true)); + assertOrPanic(!letsTryToCompareBools(false, false)); } } @@ -254,14 +255,14 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 { } test "comptime iterate over fn ptr list" { - assert(performFn('t', 1) == 6); - assert(performFn('o', 0) == 1); - assert(performFn('w', 99) == 99); + assertOrPanic(performFn('t', 1) == 6); + assertOrPanic(performFn('o', 0) == 1); + assertOrPanic(performFn('w', 99) == 99); } test "eval @setRuntimeSafety at compile-time" { const result = comptime fnWithSetRuntimeSafety(); - assert(result == 1234); + assertOrPanic(result == 1234); } fn fnWithSetRuntimeSafety() i32 { @@ -271,7 +272,7 @@ fn fnWithSetRuntimeSafety() i32 { test "eval @setFloatMode at compile-time" { const result = comptime fnWithFloatMode(); - assert(result == 1234.0); + assertOrPanic(result == 1234.0); } fn fnWithFloatMode() f32 { @@ -292,15 +293,15 @@ var simple_struct = SimpleStruct{ .field = 1234 }; const bound_fn = simple_struct.method; test "call method on bound fn referring to var instance" { - assert(bound_fn() == 1237); + assertOrPanic(bound_fn() == 1237); } test "ptr to local array argument at comptime" { comptime { var bytes: [10]u8 = undefined; modifySomeBytes(bytes[0..]); - assert(bytes[0] == 'a'); - assert(bytes[9] == 'b'); + assertOrPanic(bytes[0] == 'a'); + assertOrPanic(bytes[9] == 'b'); } } @@ -328,9 +329,9 @@ fn testCompTimeUIntComparisons(x: u32) void { } test "const ptr to variable data changes at runtime" { - assert(foo_ref.name[0] == 'a'); + assertOrPanic(foo_ref.name[0] == 'a'); foo_ref.name = "b"; - assert(foo_ref.name[0] == 'b'); + assertOrPanic(foo_ref.name[0] == 'b'); } const Foo = struct { @@ -341,8 +342,8 @@ var foo_contents = Foo{ .name = "a" }; const foo_ref = &foo_contents; test "create global array with for loop" { - assert(global_array[5] == 5 * 5); - assert(global_array[9] == 9 * 9); + assertOrPanic(global_array[5] == 5 * 5); + assertOrPanic(global_array[9] == 9 * 9); } const global_array = x: { @@ -357,7 +358,7 @@ test "compile-time downcast when the bits fit" { comptime { const spartan_count: u16 = 255; const byte = @intCast(u8, spartan_count); - assert(byte == 255); + assertOrPanic(byte == 255); } } @@ -365,44 +366,45 @@ const hi1 = "hi"; const hi2 = hi1; test "const global shares pointer with other same one" { assertEqualPtrs(&hi1[0], &hi2[0]); - comptime assert(&hi1[0] == &hi2[0]); + comptime assertOrPanic(&hi1[0] == &hi2[0]); } fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { - assert(ptr1 == ptr2); + assertOrPanic(ptr1 == ptr2); } test "@setEvalBranchQuota" { comptime { - // 1001 for the loop and then 1 more for the assert fn call + // 1001 for the loop and then 1 more for the assertOrPanic fn call @setEvalBranchQuota(1002); var i = 0; var sum = 0; while (i < 1001) : (i += 1) { sum += i; } - assert(sum == 500500); + assertOrPanic(sum == 500500); } } // TODO test "float literal at compile time not lossy" { -// TODO assert(16777216.0 + 1.0 == 16777217.0); -// TODO assert(9007199254740992.0 + 1.0 == 9007199254740993.0); +// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0); +// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0); // TODO } test "f32 at compile time is lossy" { - assert(f32(1 << 24) + 1 == 1 << 24); + assertOrPanic(f32(1 << 24) + 1 == 1 << 24); } test "f64 at compile time is lossy" { - assert(f64(1 << 53) + 1 == 1 << 53); + assertOrPanic(f64(1 << 53) + 1 == 1 << 53); } test "f128 at compile time is lossy" { - assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); + assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); } -// TODO need a better implementation of bigfloat_init_bigint -// assert(f128(1 << 113) == 10384593717069655257060992658440192); +comptime { + assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192); +} pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { return struct { @@ -413,15 +415,15 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { test "string literal used as comptime slice is memoized" { const a = "link"; const b = "link"; - comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); - comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); + comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); + comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); } test "comptime slice of undefined pointer of length 0" { const slice1 = ([*]i32)(undefined)[0..0]; - assert(slice1.len == 0); + assertOrPanic(slice1.len == 0); const slice2 = ([*]i32)(undefined)[100..100]; - assert(slice2.len == 0); + assertOrPanic(slice2.len == 0); } fn copyWithPartialInline(s: []u32, b: []u8) void { @@ -443,16 +445,16 @@ test "binary math operator in partially inlined function" { r.* = @intCast(u8, i + 1); copyWithPartialInline(s[0..], b[0..]); - assert(s[0] == 0x1020304); - assert(s[1] == 0x5060708); - assert(s[2] == 0x90a0b0c); - assert(s[3] == 0xd0e0f10); + assertOrPanic(s[0] == 0x1020304); + assertOrPanic(s[1] == 0x5060708); + assertOrPanic(s[2] == 0x90a0b0c); + assertOrPanic(s[3] == 0xd0e0f10); } test "comptime function with the same args is memoized" { comptime { - assert(MakeType(i32) == MakeType(i32)); - assert(MakeType(i32) != MakeType(f64)); + assertOrPanic(MakeType(i32) == MakeType(i32)); + assertOrPanic(MakeType(i32) != MakeType(f64)); } } @@ -468,7 +470,7 @@ test "comptime function with mutable pointer is not memoized" { const ptr = &x; increment(ptr); increment(ptr); - assert(x == 3); + assertOrPanic(x == 3); } } @@ -494,14 +496,14 @@ fn doesAlotT(comptime T: type, value: usize) T { } test "@setEvalBranchQuota at same scope as generic function call" { - assert(doesAlotT(u32, 2) == 2); + assertOrPanic(doesAlotT(u32, 2) == 2); } test "comptime slice of slice preserves comptime var" { comptime { var buff: [10]u8 = undefined; buff[0..][0..][0] = 1; - assert(buff[0..][0..][0] == 1); + assertOrPanic(buff[0..][0..][0] == 1); } } @@ -510,7 +512,7 @@ test "comptime slice of pointer preserves comptime var" { var buff: [10]u8 = undefined; var a = buff[0..].ptr; a[0..1][0] = 1; - assert(buff[0..][0..][0] == 1); + assertOrPanic(buff[0..][0..][0] == 1); } } @@ -524,9 +526,9 @@ const SingleFieldStruct = struct { test "const ptr to comptime mutable data is not memoized" { comptime { var foo = SingleFieldStruct{ .x = 1 }; - assert(foo.read_x() == 1); + assertOrPanic(foo.read_x() == 1); foo.x = 2; - assert(foo.read_x() == 2); + assertOrPanic(foo.read_x() == 2); } } @@ -535,7 +537,7 @@ test "array concat of slices gives slice" { var a: []const u8 = "aoeu"; var b: []const u8 = "asdf"; const c = a ++ b; - assert(std.mem.eql(u8, c, "aoeuasdf")); + assertOrPanic(std.mem.eql(u8, c, "aoeuasdf")); } } @@ -552,14 +554,14 @@ test "comptime shlWithOverflow" { break :amt amt; }; - assert(ct_shifted == rt_shifted); + assertOrPanic(ct_shifted == rt_shifted); } test "runtime 128 bit integer division" { var a: u128 = 152313999999999991610955792383; var b: u128 = 10000000000000000000; var c = a / b; - assert(c == 15231399999); + assertOrPanic(c == 15231399999); } pub const Info = struct { @@ -572,20 +574,20 @@ test "comptime modification of const struct field" { comptime { var res = diamond_info; res.version = 1; - assert(diamond_info.version == 0); - assert(res.version == 1); + assertOrPanic(diamond_info.version == 0); + assertOrPanic(res.version == 1); } } test "pointer to type" { comptime { var T: type = i32; - assert(T == i32); + assertOrPanic(T == i32); var ptr = &T; - assert(@typeOf(ptr) == *type); + assertOrPanic(@typeOf(ptr) == *type); ptr.* = f32; - assert(T == f32); - assert(*T == *f32); + assertOrPanic(T == f32); + assertOrPanic(*T == *f32); } } @@ -594,17 +596,17 @@ test "slice of type" { var types_array = []type{ i32, f64, type }; for (types_array) |T, i| { switch (i) { - 0 => assert(T == i32), - 1 => assert(T == f64), - 2 => assert(T == type), + 0 => assertOrPanic(T == i32), + 1 => assertOrPanic(T == f64), + 2 => assertOrPanic(T == type), else => unreachable, } } for (types_array[0..]) |T, i| { switch (i) { - 0 => assert(T == i32), - 1 => assert(T == f64), - 2 => assert(T == type), + 0 => assertOrPanic(T == i32), + 1 => assertOrPanic(T == f64), + 2 => assertOrPanic(T == type), else => unreachable, } } @@ -621,7 +623,7 @@ fn wrap(comptime T: type) Wrapper { test "function which returns struct with type field causes implicit comptime" { const ty = wrap(i32).T; - assert(ty == i32); + assertOrPanic(ty == i32); } test "call method with comptime pass-by-non-copying-value self parameter" { @@ -635,12 +637,12 @@ test "call method with comptime pass-by-non-copying-value self parameter" { const s = S{ .a = 2 }; var b = s.b(); - assert(b == 2); + assertOrPanic(b == 2); } test "@tagName of @typeId" { const str = @tagName(@typeId(u8)); - assert(std.mem.eql(u8, str, "Int")); + assertOrPanic(std.mem.eql(u8, str, "Int")); } test "setting backward branch quota just before a generic fn call" { @@ -661,8 +663,8 @@ fn testVarInsideInlineLoop(args: ...) void { comptime var i = 0; inline while (i < args.len) : (i += 1) { const x = args[i]; - if (i == 0) assert(x); - if (i == 1) assert(x == 42); + if (i == 0) assertOrPanic(x); + if (i == 1) assertOrPanic(x == 42); } } @@ -672,7 +674,7 @@ test "inline for with same type but different values" { var a: T = undefined; res += a.len; } - assert(res == 5); + assertOrPanic(res == 5); } test "refer to the type of a generic function" { @@ -686,19 +688,19 @@ fn doNothingWithType(comptime T: type) void {} test "zero extend from u0 to u1" { var zero_u0: u0 = 0; var zero_u1: u1 = zero_u0; - assert(zero_u1 == 0); + assertOrPanic(zero_u1 == 0); } test "bit shift a u1" { var x: u1 = 1; var y = x << 0; - assert(y == 1); + assertOrPanic(y == 1); } test "@intCast to a u0" { var x: u8 = 0; var y: u0 = @intCast(u0, x); - assert(y == 0); + assertOrPanic(y == 0); } test "@bytesToslice on a packed struct" { @@ -708,7 +710,7 @@ test "@bytesToslice on a packed struct" { var b = [1]u8{9}; var f = @bytesToSlice(F, b); - assert(f[0].a == 9); + assertOrPanic(f[0].a == 9); } test "comptime pointer cast array and then slice" { @@ -720,8 +722,8 @@ test "comptime pointer cast array and then slice" { const ptrB: [*]const u8 = &array; const sliceB: []const u8 = ptrB[0..2]; - assert(sliceA[1] == 2); - assert(sliceB[1] == 2); + assertOrPanic(sliceA[1] == 2); + assertOrPanic(sliceB[1] == 2); } test "slice bounds in comptime concatenation" { @@ -730,47 +732,47 @@ test "slice bounds in comptime concatenation" { break :blk b[0..1]; }; const str = "" ++ bs; - assert(str.len == 1); - assert(std.mem.eql(u8, str, "1")); + assertOrPanic(str.len == 1); + assertOrPanic(std.mem.eql(u8, str, "1")); const str2 = bs ++ ""; - assert(str2.len == 1); - assert(std.mem.eql(u8, str2, "1")); + assertOrPanic(str2.len == 1); + assertOrPanic(std.mem.eql(u8, str2, "1")); } test "comptime bitwise operators" { comptime { - assert(3 & 1 == 1); - assert(3 & -1 == 3); - assert(-3 & -1 == -3); - assert(3 | -1 == -1); - assert(-3 | -1 == -1); - assert(3 ^ -1 == -4); - assert(-3 ^ -1 == 2); - assert(~i8(-1) == 0); - assert(~i128(-1) == 0); - assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611); - assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); - assert(~u128(0) == 0xffffffffffffffffffffffffffffffff); + assertOrPanic(3 & 1 == 1); + assertOrPanic(3 & -1 == 3); + assertOrPanic(-3 & -1 == -3); + assertOrPanic(3 | -1 == -1); + assertOrPanic(-3 | -1 == -1); + assertOrPanic(3 ^ -1 == -4); + assertOrPanic(-3 ^ -1 == 2); + assertOrPanic(~i8(-1) == 0); + assertOrPanic(~i128(-1) == 0); + assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611); + assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); + assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff); } } test "*align(1) u16 is the same as *align(1:0:2) u16" { comptime { - assert(*align(1:0:2) u16 == *align(1) u16); + assertOrPanic(*align(1:0:2) u16 == *align(1) u16); // TODO add parsing support for this syntax - //assert(*align(:0:2) u16 == *u16); + //assertOrPanic(*align(:0:2) u16 == *u16); } } test "array concatenation forces comptime" { var a = oneItem(3) ++ oneItem(4); - assert(std.mem.eql(i32, a, []i32{3, 4})); + assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 })); } test "array multiplication forces comptime" { var a = oneItem(3) ** scalar(2); - assert(std.mem.eql(i32, a, []i32{3, 3})); + assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 })); } fn oneItem(x: i32) [1]i32 { diff --git a/test/cases/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig similarity index 69% rename from test/cases/field_parent_ptr.zig rename to test/stage1/behavior/field_parent_ptr.zig index 00d4e0f367..ed2487c020 100644 --- a/test/cases/field_parent_ptr.zig +++ b/test/stage1/behavior/field_parent_ptr.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "@fieldParentPtr non-first field" { testParentFieldPtr(&foo.c); @@ -25,17 +25,17 @@ const foo = Foo{ }; fn testParentFieldPtr(c: *const i32) void { - assert(c == &foo.c); + assertOrPanic(c == &foo.c); const base = @fieldParentPtr(Foo, "c", c); - assert(base == &foo); - assert(&base.c == c); + assertOrPanic(base == &foo); + assertOrPanic(&base.c == c); } fn testParentFieldPtrFirst(a: *const bool) void { - assert(a == &foo.a); + assertOrPanic(a == &foo.a); const base = @fieldParentPtr(Foo, "a", a); - assert(base == &foo); - assert(&base.a == a); + assertOrPanic(base == &foo); + assertOrPanic(&base.a == a); } diff --git a/test/cases/fn.zig b/test/stage1/behavior/fn.zig similarity index 78% rename from test/cases/fn.zig rename to test/stage1/behavior/fn.zig index 8908bd7854..3011bc41d0 100644 --- a/test/cases/fn.zig +++ b/test/stage1/behavior/fn.zig @@ -1,7 +1,7 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "params" { - assert(testParamsAdd(22, 11) == 33); + assertOrPanic(testParamsAdd(22, 11) == 33); } fn testParamsAdd(a: i32, b: i32) i32 { return a + b; @@ -21,32 +21,32 @@ test "void parameters" { fn voidFun(a: i32, b: void, c: i32, d: void) void { const v = b; const vv: void = if (a == 1) v else {}; - assert(a + c == 3); + assertOrPanic(a + c == 3); return vv; } test "mutable local variables" { var zero: i32 = 0; - assert(zero == 0); + assertOrPanic(zero == 0); var i = i32(0); while (i != 3) { i += 1; } - assert(i == 3); + assertOrPanic(i == 3); } test "separate block scopes" { { const no_conflict: i32 = 5; - assert(no_conflict == 5); + assertOrPanic(no_conflict == 5); } const c = x: { const no_conflict = i32(10); break :x no_conflict; }; - assert(c == 10); + assertOrPanic(c == 10); } test "call function with empty string" { @@ -59,7 +59,7 @@ fn @"weird function name"() i32 { return 1234; } test "weird function name" { - assert(@"weird function name"() == 1234); + assertOrPanic(@"weird function name"() == 1234); } test "implicit cast function unreachable return" { @@ -80,7 +80,7 @@ test "function pointers" { fn4, }; for (fns) |f, i| { - assert(f() == @intCast(u32, i) + 5); + assertOrPanic(f() == @intCast(u32, i) + 5); } } fn fn1() u32 { @@ -97,7 +97,7 @@ fn fn4() u32 { } test "inline function call" { - assert(@inlineCall(add, 3, 9) == 12); + assertOrPanic(@inlineCall(add, 3, 9) == 12); } fn add(a: i32, b: i32) i32 { @@ -110,7 +110,7 @@ test "number literal as an argument" { } fn numberLiteralArg(a: var) void { - assert(a == 3); + assertOrPanic(a == 3); } test "assign inline fn to const variable" { @@ -121,7 +121,7 @@ test "assign inline fn to const variable" { inline fn inlineFn() void {} test "pass by non-copying value" { - assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); + assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } const Point = struct { @@ -134,17 +134,17 @@ fn addPointCoords(pt: Point) i32 { } test "pass by non-copying value through var arg" { - assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); + assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); } fn addPointCoordsVar(pt: var) i32 { - comptime assert(@typeOf(pt) == Point); + comptime assertOrPanic(@typeOf(pt) == Point); return pt.x + pt.y; } test "pass by non-copying value as method" { var pt = Point2{ .x = 1, .y = 2 }; - assert(pt.addPointCoords() == 3); + assertOrPanic(pt.addPointCoords() == 3); } const Point2 = struct { @@ -158,7 +158,7 @@ const Point2 = struct { test "pass by non-copying value as method, which is generic" { var pt = Point3{ .x = 1, .y = 2 }; - assert(pt.addPointCoords(i32) == 3); + assertOrPanic(pt.addPointCoords(i32) == 3); } const Point3 = struct { @@ -173,7 +173,7 @@ const Point3 = struct { test "pass by non-copying value as method, at comptime" { comptime { var pt = Point2{ .x = 1, .y = 2 }; - assert(pt.addPointCoords() == 3); + assertOrPanic(pt.addPointCoords() == 3); } } @@ -189,7 +189,7 @@ fn outer(y: u32) fn (u32) u32 { test "return inner function which references comptime variable of outer function" { var func = outer(10); - assert(func(3) == 7); + assertOrPanic(func(3) == 7); } test "extern struct with stdcallcc fn pointer" { @@ -203,5 +203,6 @@ test "extern struct with stdcallcc fn pointer" { var s: S = undefined; s.ptr = S.foo; - assert(s.ptr() == 1234); + assertOrPanic(s.ptr() == 1234); } + diff --git a/test/cases/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig similarity index 72% rename from test/cases/fn_in_struct_in_comptime.zig rename to test/stage1/behavior/fn_in_struct_in_comptime.zig index fabb57e9cb..0af076d40a 100644 --- a/test/cases/fn_in_struct_in_comptime.zig +++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; fn get_foo() fn (*u8) usize { comptime { @@ -13,5 +13,5 @@ fn get_foo() fn (*u8) usize { test "define a function in an anonymous struct in comptime" { const foo = get_foo(); - assert(foo(@intToPtr(*u8, 12345)) == 12345); + assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345); } diff --git a/test/cases/for.zig b/test/stage1/behavior/for.zig similarity index 89% rename from test/cases/for.zig rename to test/stage1/behavior/for.zig index aecd8b9a07..b6d1ef24c4 100644 --- a/test/cases/for.zig +++ b/test/stage1/behavior/for.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const mem = std.mem; test "continue in for loop" { @@ -26,7 +26,7 @@ test "for loop with pointer elem var" { var target: [source.len]u8 = undefined; mem.copy(u8, target[0..], source); mangleString(target[0..]); - assert(mem.eql(u8, target, "bcdefgh")); + assertOrPanic(mem.eql(u8, target, "bcdefgh")); } fn mangleString(s: []u8) void { for (s) |*c| { @@ -68,7 +68,7 @@ test "basic for loop" { buf_index += 1; } - assert(mem.eql(u8, buffer[0..buf_index], expected_result)); + assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result)); } test "break from outer for loop" { @@ -85,7 +85,7 @@ fn testBreakOuter() void { break :outer; } } - assert(count == 1); + assertOrPanic(count == 1); } test "continue outer for loop" { @@ -102,5 +102,5 @@ fn testContinueOuter() void { continue :outer; } } - assert(counter == array.len); + assertOrPanic(counter == array.len); } diff --git a/test/cases/generics.zig b/test/stage1/behavior/generics.zig similarity index 68% rename from test/cases/generics.zig rename to test/stage1/behavior/generics.zig index 52aa013989..a0928634a7 100644 --- a/test/cases/generics.zig +++ b/test/stage1/behavior/generics.zig @@ -1,9 +1,9 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "simple generic fn" { - assert(max(i32, 3, -1) == 3); - assert(max(f32, 0.123, 0.456) == 0.456); - assert(add(2, 3) == 5); + assertOrPanic(max(i32, 3, -1) == 3); + assertOrPanic(max(f32, 0.123, 0.456) == 0.456); + assertOrPanic(add(2, 3) == 5); } fn max(comptime T: type, a: T, b: T) T { @@ -16,7 +16,7 @@ fn add(comptime a: i32, b: i32) i32 { const the_max = max(u32, 1234, 5678); test "compile time generic eval" { - assert(the_max == 5678); + assertOrPanic(the_max == 5678); } fn gimmeTheBigOne(a: u32, b: u32) u32 { @@ -32,19 +32,19 @@ fn sameButWithFloats(a: f64, b: f64) f64 { } test "fn with comptime args" { - assert(gimmeTheBigOne(1234, 5678) == 5678); - assert(shouldCallSameInstance(34, 12) == 34); - assert(sameButWithFloats(0.43, 0.49) == 0.49); + assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678); + assertOrPanic(shouldCallSameInstance(34, 12) == 34); + assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49); } test "var params" { - assert(max_i32(12, 34) == 34); - assert(max_f64(1.2, 3.4) == 3.4); + assertOrPanic(max_i32(12, 34) == 34); + assertOrPanic(max_f64(1.2, 3.4) == 3.4); } comptime { - assert(max_i32(12, 34) == 34); - assert(max_f64(1.2, 3.4) == 3.4); + assertOrPanic(max_i32(12, 34) == 34); + assertOrPanic(max_f64(1.2, 3.4) == 3.4); } fn max_var(a: var, b: var) @typeOf(a + b) { @@ -76,8 +76,8 @@ test "function with return type type" { var list2: List(i32) = undefined; list.length = 10; list2.length = 10; - assert(list.prealloc_items.len == 8); - assert(list2.prealloc_items.len == 8); + assertOrPanic(list.prealloc_items.len == 8); + assertOrPanic(list2.prealloc_items.len == 8); } test "generic struct" { @@ -89,9 +89,9 @@ test "generic struct" { .value = true, .next = null, }; - assert(a1.value == 13); - assert(a1.value == a1.getVal()); - assert(b1.getVal()); + assertOrPanic(a1.value == 13); + assertOrPanic(a1.value == a1.getVal()); + assertOrPanic(b1.getVal()); } fn GenNode(comptime T: type) type { return struct { @@ -104,7 +104,7 @@ fn GenNode(comptime T: type) type { } test "const decls in struct" { - assert(GenericDataThing(3).count_plus_one == 4); + assertOrPanic(GenericDataThing(3).count_plus_one == 4); } fn GenericDataThing(comptime count: isize) type { return struct { @@ -113,15 +113,15 @@ fn GenericDataThing(comptime count: isize) type { } test "use generic param in generic param" { - assert(aGenericFn(i32, 3, 4) == 7); + assertOrPanic(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(comptime T: type, comptime a: T, b: T) T { return a + b; } test "generic fn with implicit cast" { - assert(getFirstByte(u8, []u8{13}) == 13); - assert(getFirstByte(u16, []u16{ + assertOrPanic(getFirstByte(u8, []u8{13}) == 13); + assertOrPanic(getFirstByte(u16, []u16{ 0, 13, }) == 0); @@ -146,6 +146,6 @@ fn foo2(arg: var) bool { } test "array of generic fns" { - assert(foos[0](true)); - assert(!foos[1](true)); + assertOrPanic(foos[0](true)); + assertOrPanic(!foos[1](true)); } diff --git a/test/cases/if.zig b/test/stage1/behavior/if.zig similarity index 85% rename from test/cases/if.zig rename to test/stage1/behavior/if.zig index 808936bfa5..58d1b8fd73 100644 --- a/test/cases/if.zig +++ b/test/stage1/behavior/if.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "if statements" { shouldBeEqual(1, 1); @@ -24,7 +24,7 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void { } test "else if expression" { - assert(elseIfExpressionF(1) == 1); + assertOrPanic(elseIfExpressionF(1) == 1); } fn elseIfExpressionF(c: u8) u8 { if (c == 0) { diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig new file mode 100644 index 0000000000..736e4c219d --- /dev/null +++ b/test/stage1/behavior/import.zig @@ -0,0 +1,10 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const a_namespace = @import("import/a_namespace.zig"); + +test "call fn via namespace lookup" { + assertOrPanic(a_namespace.foo() == 1234); +} + +test "importing the same thing gives the same import" { + assertOrPanic(@import("std") == @import("std")); +} diff --git a/test/cases/import/a_namespace.zig b/test/stage1/behavior/import/a_namespace.zig similarity index 100% rename from test/cases/import/a_namespace.zig rename to test/stage1/behavior/import/a_namespace.zig diff --git a/test/cases/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig similarity index 78% rename from test/cases/incomplete_struct_param_tld.zig rename to test/stage1/behavior/incomplete_struct_param_tld.zig index f1ac03a292..d062311b2e 100644 --- a/test/cases/incomplete_struct_param_tld.zig +++ b/test/stage1/behavior/incomplete_struct_param_tld.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const A = struct { b: B, @@ -26,5 +26,5 @@ test "incomplete struct param top level declaration" { .c = C{ .x = 13 }, }, }; - assert(foo(a) == 13); + assertOrPanic(foo(a) == 13); } diff --git a/test/cases/inttoptr.zig b/test/stage1/behavior/inttoptr.zig similarity index 99% rename from test/cases/inttoptr.zig rename to test/stage1/behavior/inttoptr.zig index ba3cc52f09..bf657fc86a 100644 --- a/test/cases/inttoptr.zig +++ b/test/stage1/behavior/inttoptr.zig @@ -24,4 +24,3 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { return; } } - diff --git a/test/cases/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig similarity index 64% rename from test/cases/ir_block_deps.zig rename to test/stage1/behavior/ir_block_deps.zig index 5c1b18c00e..bc61e11df7 100644 --- a/test/cases/ir_block_deps.zig +++ b/test/stage1/behavior/ir_block_deps.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; fn foo(id: u64) !i32 { return switch (id) { @@ -16,6 +16,6 @@ fn getErrInt() anyerror!i32 { } test "ir block deps" { - assert((foo(1) catch unreachable) == 0); - assert((foo(2) catch unreachable) == 0); + assertOrPanic((foo(1) catch unreachable) == 0); + assertOrPanic((foo(2) catch unreachable) == 0); } diff --git a/test/cases/math.zig b/test/stage1/behavior/math.zig similarity index 56% rename from test/cases/math.zig rename to test/stage1/behavior/math.zig index 7d6b1bd9ac..9d6a5a4997 100644 --- a/test/cases/math.zig +++ b/test/stage1/behavior/math.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -8,57 +8,57 @@ test "division" { comptime testDivision(); } fn testDivision() void { - assert(div(u32, 13, 3) == 4); - assert(div(f16, 1.0, 2.0) == 0.5); - assert(div(f32, 1.0, 2.0) == 0.5); + assertOrPanic(div(u32, 13, 3) == 4); + assertOrPanic(div(f16, 1.0, 2.0) == 0.5); + assertOrPanic(div(f32, 1.0, 2.0) == 0.5); - assert(divExact(u32, 55, 11) == 5); - assert(divExact(i32, -55, 11) == -5); - assert(divExact(f16, 55.0, 11.0) == 5.0); - assert(divExact(f16, -55.0, 11.0) == -5.0); - assert(divExact(f32, 55.0, 11.0) == 5.0); - assert(divExact(f32, -55.0, 11.0) == -5.0); + assertOrPanic(divExact(u32, 55, 11) == 5); + assertOrPanic(divExact(i32, -55, 11) == -5); + assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0); + assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0); + assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0); + assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0); - assert(divFloor(i32, 5, 3) == 1); - assert(divFloor(i32, -5, 3) == -2); - assert(divFloor(f16, 5.0, 3.0) == 1.0); - assert(divFloor(f16, -5.0, 3.0) == -2.0); - assert(divFloor(f32, 5.0, 3.0) == 1.0); - assert(divFloor(f32, -5.0, 3.0) == -2.0); - assert(divFloor(i32, -0x80000000, -2) == 0x40000000); - assert(divFloor(i32, 0, -0x80000000) == 0); - assert(divFloor(i32, -0x40000001, 0x40000000) == -2); - assert(divFloor(i32, -0x80000000, 1) == -0x80000000); + assertOrPanic(divFloor(i32, 5, 3) == 1); + assertOrPanic(divFloor(i32, -5, 3) == -2); + assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0); + assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0); + assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0); + assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0); + assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000); + assertOrPanic(divFloor(i32, 0, -0x80000000) == 0); + assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2); + assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000); - assert(divTrunc(i32, 5, 3) == 1); - assert(divTrunc(i32, -5, 3) == -1); - assert(divTrunc(f16, 5.0, 3.0) == 1.0); - assert(divTrunc(f16, -5.0, 3.0) == -1.0); - assert(divTrunc(f32, 5.0, 3.0) == 1.0); - assert(divTrunc(f32, -5.0, 3.0) == -1.0); - assert(divTrunc(f64, 5.0, 3.0) == 1.0); - assert(divTrunc(f64, -5.0, 3.0) == -1.0); + assertOrPanic(divTrunc(i32, 5, 3) == 1); + assertOrPanic(divTrunc(i32, -5, 3) == -1); + assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0); + assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0); + assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0); comptime { - assert( + assertOrPanic( 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, ); - assert( + assertOrPanic( @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, ); - assert( + assertOrPanic( 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, ); - assert( + assertOrPanic( @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, ); - assert( + assertOrPanic( @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, ); - assert( + assertOrPanic( @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, ); - assert( + assertOrPanic( 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, ); } @@ -78,9 +78,9 @@ fn divTrunc(comptime T: type, a: T, b: T) T { test "@addWithOverflow" { var result: u8 = undefined; - assert(@addWithOverflow(u8, 250, 100, &result)); - assert(!@addWithOverflow(u8, 100, 150, &result)); - assert(result == 250); + assertOrPanic(@addWithOverflow(u8, 250, 100, &result)); + assertOrPanic(!@addWithOverflow(u8, 100, 150, &result)); + assertOrPanic(result == 250); } // TODO test mulWithOverflow @@ -88,9 +88,9 @@ test "@addWithOverflow" { test "@shlWithOverflow" { var result: u16 = undefined; - assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - assert(result == 0b1011111111111100); + assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); + assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); + assertOrPanic(result == 0b1011111111111100); } test "@clz" { @@ -99,11 +99,11 @@ test "@clz" { } fn testClz() void { - assert(clz(u8(0b00001010)) == 4); - assert(clz(u8(0b10001010)) == 0); - assert(clz(u8(0b00000000)) == 8); - assert(clz(u128(0xffffffffffffffff)) == 64); - assert(clz(u128(0x10000000000000000)) == 63); + assertOrPanic(clz(u8(0b00001010)) == 4); + assertOrPanic(clz(u8(0b10001010)) == 0); + assertOrPanic(clz(u8(0b00000000)) == 8); + assertOrPanic(clz(u128(0xffffffffffffffff)) == 64); + assertOrPanic(clz(u128(0x10000000000000000)) == 63); } fn clz(x: var) usize { @@ -116,9 +116,9 @@ test "@ctz" { } fn testCtz() void { - assert(ctz(u8(0b10100000)) == 5); - assert(ctz(u8(0b10001010)) == 1); - assert(ctz(u8(0b00000000)) == 8); + assertOrPanic(ctz(u8(0b10100000)) == 5); + assertOrPanic(ctz(u8(0b10001010)) == 1); + assertOrPanic(ctz(u8(0b00000000)) == 8); } fn ctz(x: var) usize { @@ -128,27 +128,27 @@ fn ctz(x: var) usize { test "assignment operators" { var i: u32 = 0; i += 5; - assert(i == 5); + assertOrPanic(i == 5); i -= 2; - assert(i == 3); + assertOrPanic(i == 3); i *= 20; - assert(i == 60); + assertOrPanic(i == 60); i /= 3; - assert(i == 20); + assertOrPanic(i == 20); i %= 11; - assert(i == 9); + assertOrPanic(i == 9); i <<= 1; - assert(i == 18); + assertOrPanic(i == 18); i >>= 2; - assert(i == 4); + assertOrPanic(i == 4); i = 6; i &= 5; - assert(i == 4); + assertOrPanic(i == 4); i ^= 6; - assert(i == 2); + assertOrPanic(i == 2); i = 6; i |= 3; - assert(i == 7); + assertOrPanic(i == 7); } test "three expr in a row" { @@ -170,14 +170,14 @@ fn testThreeExprInARow(f: bool, t: bool) void { assertFalse(i32(7) != --(i32(7))); } fn assertFalse(b: bool) void { - assert(!b); + assertOrPanic(!b); } test "const number literal" { const one = 1; const eleven = ten + one; - assert(eleven == 11); + assertOrPanic(eleven == 11); } const ten = 10; @@ -187,9 +187,9 @@ test "unsigned wrapping" { } fn testUnsignedWrappingEval(x: u32) void { const zero = x +% 1; - assert(zero == 0); + assertOrPanic(zero == 0); const orig = zero -% 1; - assert(orig == maxInt(u32)); + assertOrPanic(orig == maxInt(u32)); } test "signed wrapping" { @@ -198,9 +198,9 @@ test "signed wrapping" { } fn testSignedWrappingEval(x: i32) void { const min_val = x +% 1; - assert(min_val == minInt(i32)); + assertOrPanic(min_val == minInt(i32)); const max_val = min_val -% 1; - assert(max_val == maxInt(i32)); + assertOrPanic(max_val == maxInt(i32)); } test "negation wrapping" { @@ -208,9 +208,9 @@ test "negation wrapping" { comptime testNegationWrappingEval(minInt(i16)); } fn testNegationWrappingEval(x: i16) void { - assert(x == -32768); + assertOrPanic(x == -32768); const neg = -%x; - assert(neg == -32768); + assertOrPanic(neg == -32768); } test "unsigned 64-bit division" { @@ -219,8 +219,8 @@ test "unsigned 64-bit division" { } fn test_u64_div() void { const result = divWithResult(1152921504606846976, 34359738365); - assert(result.quotient == 33554432); - assert(result.remainder == 100663296); + assertOrPanic(result.quotient == 33554432); + assertOrPanic(result.remainder == 100663296); } fn divWithResult(a: u64, b: u64) DivResult { return DivResult{ @@ -234,36 +234,36 @@ const DivResult = struct { }; test "binary not" { - assert(comptime x: { + assertOrPanic(comptime x: { break :x ~u16(0b1010101010101010) == 0b0101010101010101; }); - assert(comptime x: { + assertOrPanic(comptime x: { break :x ~u64(2147483647) == 18446744071562067968; }); testBinaryNot(0b1010101010101010); } fn testBinaryNot(x: u16) void { - assert(~x == 0b0101010101010101); + assertOrPanic(~x == 0b0101010101010101); } test "small int addition" { var x: @IntType(false, 2) = 0; - assert(x == 0); + assertOrPanic(x == 0); x += 1; - assert(x == 1); + assertOrPanic(x == 1); x += 1; - assert(x == 2); + assertOrPanic(x == 2); x += 1; - assert(x == 3); + assertOrPanic(x == 3); var result: @typeOf(x) = 3; - assert(@addWithOverflow(@typeOf(x), x, 1, &result)); + assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result)); - assert(result == 0); + assertOrPanic(result == 0); } test "float equality" { @@ -276,20 +276,20 @@ test "float equality" { fn testFloatEqualityImpl(x: f64, y: f64) void { const y2 = x + 1.0; - assert(y == y2); + assertOrPanic(y == y2); } test "allow signed integer division/remainder when values are comptime known and positive or exact" { - assert(5 / 3 == 1); - assert(-5 / -3 == 1); - assert(-6 / 3 == -2); + assertOrPanic(5 / 3 == 1); + assertOrPanic(-5 / -3 == 1); + assertOrPanic(-6 / 3 == -2); - assert(5 % 3 == 2); - assert(-6 % 3 == 0); + assertOrPanic(5 % 3 == 2); + assertOrPanic(-6 % 3 == 0); } test "hex float literal parsing" { - comptime assert(0x1.0 == 1.0); + comptime assertOrPanic(0x1.0 == 1.0); } test "quad hex float literal parsing in range" { @@ -304,7 +304,7 @@ test "quad hex float literal parsing accurate" { // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. const expected: u128 = 0x3fff1111222233334444555566667777; - assert(@bitCast(u128, a) == expected); + assertOrPanic(@bitCast(u128, a) == expected); } test "hex float literal within range" { @@ -319,7 +319,7 @@ test "truncating shift left" { } fn testShlTrunc(x: u16) void { const shifted = x << 1; - assert(shifted == 65534); + assertOrPanic(shifted == 65534); } test "truncating shift right" { @@ -328,7 +328,7 @@ test "truncating shift right" { } fn testShrTrunc(x: u16) void { const shifted = x >> 1; - assert(shifted == 32767); + assertOrPanic(shifted == 32767); } test "exact shift left" { @@ -337,7 +337,7 @@ test "exact shift left" { } fn testShlExact(x: u8) void { const shifted = @shlExact(x, 2); - assert(shifted == 0b11010100); + assertOrPanic(shifted == 0b11010100); } test "exact shift right" { @@ -346,22 +346,22 @@ test "exact shift right" { } fn testShrExact(x: u8) void { const shifted = @shrExact(x, 2); - assert(shifted == 0b00101101); + assertOrPanic(shifted == 0b00101101); } test "comptime_int addition" { comptime { - assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); - assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); + assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); + assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); } } test "comptime_int multiplication" { comptime { - assert( + assertOrPanic( 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, ); - assert( + assertOrPanic( 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, ); } @@ -369,7 +369,7 @@ test "comptime_int multiplication" { test "comptime_int shifting" { comptime { - assert((u128(1) << 127) == 0x80000000000000000000000000000000); + assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000); } } @@ -377,16 +377,16 @@ test "comptime_int multi-limb shift and mask" { comptime { var a = 0xefffffffa0000001eeeeeeefaaaaaaab; - assert(u32(a & 0xffffffff) == 0xaaaaaaab); + assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab); a >>= 32; - assert(u32(a & 0xffffffff) == 0xeeeeeeef); + assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef); a >>= 32; - assert(u32(a & 0xffffffff) == 0xa0000001); + assertOrPanic(u32(a & 0xffffffff) == 0xa0000001); a >>= 32; - assert(u32(a & 0xffffffff) == 0xefffffff); + assertOrPanic(u32(a & 0xffffffff) == 0xefffffff); a >>= 32; - assert(a == 0); + assertOrPanic(a == 0); } } @@ -394,7 +394,7 @@ test "comptime_int multi-limb partial shift right" { comptime { var a = 0x1ffffffffeeeeeeee; a >>= 16; - assert(a == 0x1ffffffffeeee); + assertOrPanic(a == 0x1ffffffffeeee); } } @@ -404,23 +404,23 @@ test "xor" { } fn test_xor() void { - assert(0xFF ^ 0x00 == 0xFF); - assert(0xF0 ^ 0x0F == 0xFF); - assert(0xFF ^ 0xF0 == 0x0F); - assert(0xFF ^ 0x0F == 0xF0); - assert(0xFF ^ 0xFF == 0x00); + assertOrPanic(0xFF ^ 0x00 == 0xFF); + assertOrPanic(0xF0 ^ 0x0F == 0xFF); + assertOrPanic(0xFF ^ 0xF0 == 0x0F); + assertOrPanic(0xFF ^ 0x0F == 0xF0); + assertOrPanic(0xFF ^ 0xFF == 0x00); } test "comptime_int xor" { comptime { - assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); - assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); - assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); - assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); - assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); + assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); + assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); + assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); + assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); + assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); } } @@ -434,23 +434,23 @@ fn make_f128(x: f128) f128 { } fn test_f128() void { - assert(@sizeOf(f128) == 16); - assert(make_f128(1.0) == 1.0); - assert(make_f128(1.0) != 1.1); - assert(make_f128(1.0) > 0.9); - assert(make_f128(1.0) >= 0.9); - assert(make_f128(1.0) >= 1.0); + assertOrPanic(@sizeOf(f128) == 16); + assertOrPanic(make_f128(1.0) == 1.0); + assertOrPanic(make_f128(1.0) != 1.1); + assertOrPanic(make_f128(1.0) > 0.9); + assertOrPanic(make_f128(1.0) >= 0.9); + assertOrPanic(make_f128(1.0) >= 1.0); should_not_be_zero(1.0); } fn should_not_be_zero(x: f128) void { - assert(x != 0.0); + assertOrPanic(x != 0.0); } test "comptime float rem int" { comptime { var x = f32(1) % 2; - assert(x == 1.0); + assertOrPanic(x == 1.0); } } @@ -465,8 +465,8 @@ test "remainder division" { } fn remdiv(comptime T: type) void { - assert(T(1) == T(1) % T(2)); - assert(T(1) == T(7) % T(3)); + assertOrPanic(T(1) == T(1) % T(2)); + assertOrPanic(T(1) == T(7) % T(3)); } test "@sqrt" { @@ -480,19 +480,19 @@ test "@sqrt" { const x = 14.0; const y = x * x; const z = @sqrt(@typeOf(y), y); - comptime assert(z == x); + comptime assertOrPanic(z == x); } fn testSqrt(comptime T: type, x: T) void { - assert(@sqrt(T, x * x) == x); + assertOrPanic(@sqrt(T, x * x) == x); } test "comptime_int param and return" { const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); - assert(a == 137114567242441932203689521744947848950); + assertOrPanic(a == 137114567242441932203689521744947848950); const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); - assert(b == 985095453608931032642182098849559179469148836107390954364380); + assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380); } fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { diff --git a/test/cases/merge_error_sets.zig b/test/stage1/behavior/merge_error_sets.zig similarity index 100% rename from test/cases/merge_error_sets.zig rename to test/stage1/behavior/merge_error_sets.zig diff --git a/test/cases/misc.zig b/test/stage1/behavior/misc.zig similarity index 61% rename from test/cases/misc.zig rename to test/stage1/behavior/misc.zig index 1a34d54e9e..8d2555dddd 100644 --- a/test/cases/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const mem = std.mem; const cstr = std.cstr; const builtin = @import("builtin"); @@ -26,38 +26,38 @@ test "call disabled extern fn" { } test "@IntType builtin" { - assert(@IntType(true, 8) == i8); - assert(@IntType(true, 16) == i16); - assert(@IntType(true, 32) == i32); - assert(@IntType(true, 64) == i64); + assertOrPanic(@IntType(true, 8) == i8); + assertOrPanic(@IntType(true, 16) == i16); + assertOrPanic(@IntType(true, 32) == i32); + assertOrPanic(@IntType(true, 64) == i64); - assert(@IntType(false, 8) == u8); - assert(@IntType(false, 16) == u16); - assert(@IntType(false, 32) == u32); - assert(@IntType(false, 64) == u64); + assertOrPanic(@IntType(false, 8) == u8); + assertOrPanic(@IntType(false, 16) == u16); + assertOrPanic(@IntType(false, 32) == u32); + assertOrPanic(@IntType(false, 64) == u64); - assert(i8.bit_count == 8); - assert(i16.bit_count == 16); - assert(i32.bit_count == 32); - assert(i64.bit_count == 64); + assertOrPanic(i8.bit_count == 8); + assertOrPanic(i16.bit_count == 16); + assertOrPanic(i32.bit_count == 32); + assertOrPanic(i64.bit_count == 64); - assert(i8.is_signed); - assert(i16.is_signed); - assert(i32.is_signed); - assert(i64.is_signed); - assert(isize.is_signed); + assertOrPanic(i8.is_signed); + assertOrPanic(i16.is_signed); + assertOrPanic(i32.is_signed); + assertOrPanic(i64.is_signed); + assertOrPanic(isize.is_signed); - assert(!u8.is_signed); - assert(!u16.is_signed); - assert(!u32.is_signed); - assert(!u64.is_signed); - assert(!usize.is_signed); + assertOrPanic(!u8.is_signed); + assertOrPanic(!u16.is_signed); + assertOrPanic(!u32.is_signed); + assertOrPanic(!u64.is_signed); + assertOrPanic(!usize.is_signed); } test "floating point primitive bit counts" { - assert(f16.bit_count == 16); - assert(f32.bit_count == 32); - assert(f64.bit_count == 64); + assertOrPanic(f16.bit_count == 16); + assertOrPanic(f32.bit_count == 32); + assertOrPanic(f64.bit_count == 64); } test "short circuit" { @@ -72,7 +72,7 @@ fn testShortCircuit(f: bool, t: bool) void { var hit_4 = f; if (t or x: { - assert(f); + assertOrPanic(f); break :x f; }) { hit_1 = t; @@ -81,31 +81,31 @@ fn testShortCircuit(f: bool, t: bool) void { hit_2 = t; break :x f; }) { - assert(f); + assertOrPanic(f); } if (t and x: { hit_3 = t; break :x f; }) { - assert(f); + assertOrPanic(f); } if (f and x: { - assert(f); + assertOrPanic(f); break :x f; }) { - assert(f); + assertOrPanic(f); } else { hit_4 = t; } - assert(hit_1); - assert(hit_2); - assert(hit_3); - assert(hit_4); + assertOrPanic(hit_1); + assertOrPanic(hit_2); + assertOrPanic(hit_3); + assertOrPanic(hit_4); } test "truncate" { - assert(testTruncate(0x10fd) == 0xfd); + assertOrPanic(testTruncate(0x10fd) == 0xfd); } fn testTruncate(x: u32) u8 { return @truncate(u8, x); @@ -116,16 +116,16 @@ fn first4KeysOfHomeRow() []const u8 { } test "return string from function" { - assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); + assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); } const g1: i32 = 1233 + 1; var g2: i32 = 0; test "global variables" { - assert(g2 == 0); + assertOrPanic(g2 == 0); g2 = g1; - assert(g2 == 1234); + assertOrPanic(g2 == 1234); } test "memcpy and memset intrinsics" { @@ -142,7 +142,7 @@ test "builtin static eval" { const x: i32 = comptime x: { break :x 1 + 2 + 3; }; - assert(x == comptime 6); + assertOrPanic(x == comptime 6); } test "slicing" { @@ -163,7 +163,7 @@ test "slicing" { test "constant equal function pointers" { const alias = emptyFn; - assert(comptime x: { + assertOrPanic(comptime x: { break :x emptyFn == alias; }); } @@ -171,25 +171,25 @@ test "constant equal function pointers" { fn emptyFn() void {} test "hex escape" { - assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); + assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); } test "string concatenation" { - assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); + assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); } test "array mult operator" { - assert(mem.eql(u8, "ab" ** 5, "ababababab")); + assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab")); } test "string escapes" { - assert(mem.eql(u8, "\"", "\x22")); - assert(mem.eql(u8, "\'", "\x27")); - assert(mem.eql(u8, "\n", "\x0a")); - assert(mem.eql(u8, "\r", "\x0d")); - assert(mem.eql(u8, "\t", "\x09")); - assert(mem.eql(u8, "\\", "\x5c")); - assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); + assertOrPanic(mem.eql(u8, "\"", "\x22")); + assertOrPanic(mem.eql(u8, "\'", "\x27")); + assertOrPanic(mem.eql(u8, "\n", "\x0a")); + assertOrPanic(mem.eql(u8, "\r", "\x0d")); + assertOrPanic(mem.eql(u8, "\t", "\x09")); + assertOrPanic(mem.eql(u8, "\\", "\x5c")); + assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); } test "multiline string" { @@ -199,7 +199,7 @@ test "multiline string" { \\three ; const s2 = "one\ntwo)\nthree"; - assert(mem.eql(u8, s1, s2)); + assertOrPanic(mem.eql(u8, s1, s2)); } test "multiline C string" { @@ -209,11 +209,11 @@ test "multiline C string" { c\\three ; const s2 = c"one\ntwo)\nthree"; - assert(cstr.cmp(s1, s2) == 0); + assertOrPanic(cstr.cmp(s1, s2) == 0); } test "type equality" { - assert(*const u8 != *u8); + assertOrPanic(*const u8 != *u8); } const global_a: i32 = 1234; @@ -221,7 +221,7 @@ const global_b: *const i32 = &global_a; const global_c: *const f32 = @ptrCast(*const f32, global_b); test "compile time global reinterpret" { const d = @ptrCast(*const i32, global_c); - assert(d.* == 1234); + assertOrPanic(d.* == 1234); } test "explicit cast maybe pointers" { @@ -247,8 +247,8 @@ test "cast undefined" { fn testCastUndefined(x: []const u8) void {} test "cast small unsigned to larger signed" { - assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); - assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); + assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200)); + assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); } fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; @@ -258,7 +258,7 @@ fn castSmallUnsignedToLargerSigned2(x: u16) i64 { } test "implicit cast after unreachable" { - assert(outer() == 1234); + assertOrPanic(outer() == 1234); } fn inner() i32 { return 1234; @@ -273,13 +273,13 @@ test "pointer dereferencing" { y.* += 1; - assert(x == 4); - assert(y.* == 4); + assertOrPanic(x == 4); + assertOrPanic(y.* == 4); } test "call result of if else expression" { - assert(mem.eql(u8, f2(true), "a")); - assert(mem.eql(u8, f2(false), "b")); + assertOrPanic(mem.eql(u8, f2(true), "a")); + assertOrPanic(mem.eql(u8, f2(false), "b")); } fn f2(x: bool) []const u8 { return (if (x) fA else fB)(); @@ -321,8 +321,8 @@ const test3_bar = Test3Foo{ .Two = 13 }; fn test3_1(f: Test3Foo) void { switch (f) { Test3Foo.Three => |pt| { - assert(pt.x == 3); - assert(pt.y == 4); + assertOrPanic(pt.x == 3); + assertOrPanic(pt.y == 4); }, else => unreachable, } @@ -330,14 +330,14 @@ fn test3_1(f: Test3Foo) void { fn test3_2(f: Test3Foo) void { switch (f) { Test3Foo.Two => |x| { - assert(x == 13); + assertOrPanic(x == 13); }, else => unreachable, } } test "character literals" { - assert('\'' == single_quote); + assertOrPanic('\'' == single_quote); } const single_quote = '\''; @@ -346,13 +346,13 @@ test "take address of parameter" { } fn testTakeAddressOfParameter(f: f32) void { const f_ptr = &f; - assert(f_ptr.* == 12.34); + assertOrPanic(f_ptr.* == 12.34); } test "pointer comparison" { const a = ([]const u8)("a"); const b = &a; - assert(ptrEql(b, b)); + assertOrPanic(ptrEql(b, b)); } fn ptrEql(a: *const []const u8, b: *const []const u8) bool { return a == b; @@ -367,36 +367,31 @@ test "C string concatenation" { { var i: u32 = 0; while (i < len_with_null) : (i += 1) { - assert(a[i] == b[i]); + assertOrPanic(a[i] == b[i]); } } - assert(a[len] == 0); - assert(b[len] == 0); + assertOrPanic(a[len] == 0); + assertOrPanic(b[len] == 0); } test "cast slice to u8 slice" { - assert(@sizeOf(i32) == 4); - var big_thing_array = []i32{ - 1, - 2, - 3, - 4, - }; + assertOrPanic(@sizeOf(i32) == 4); + var big_thing_array = []i32{ 1, 2, 3, 4 }; const big_thing_slice: []i32 = big_thing_array[0..]; const bytes = @sliceToBytes(big_thing_slice); - assert(bytes.len == 4 * 4); + assertOrPanic(bytes.len == 4 * 4); bytes[4] = 0; bytes[5] = 0; bytes[6] = 0; bytes[7] = 0; - assert(big_thing_slice[1] == 0); + assertOrPanic(big_thing_slice[1] == 0); const big_thing_again = @bytesToSlice(i32, bytes); - assert(big_thing_again[2] == 3); + assertOrPanic(big_thing_again[2] == 3); big_thing_again[2] = -1; - assert(bytes[8] == maxInt(u8)); - assert(bytes[9] == maxInt(u8)); - assert(bytes[10] == maxInt(u8)); - assert(bytes[11] == maxInt(u8)); + assertOrPanic(bytes[8] == maxInt(u8)); + assertOrPanic(bytes[9] == maxInt(u8)); + assertOrPanic(bytes[10] == maxInt(u8)); + assertOrPanic(bytes[11] == maxInt(u8)); } test "pointer to void return type" { @@ -413,7 +408,7 @@ fn testPointerToVoidReturnType2() *const void { test "non const ptr to aliased type" { const int = i32; - assert(?*int == ?*i32); + assertOrPanic(?*int == ?*i32); } test "array 2D const double ptr" { @@ -426,8 +421,8 @@ test "array 2D const double ptr" { fn testArray2DConstDoublePtr(ptr: *const f32) void { const ptr2 = @ptrCast([*]const f32, ptr); - assert(ptr2[0] == 1.0); - assert(ptr2[1] == 2.0); + assertOrPanic(ptr2[0] == 1.0); + assertOrPanic(ptr2[1] == 2.0); } const Tid = builtin.TypeId; @@ -449,32 +444,32 @@ const AUnion = union { test "@typeId" { comptime { - assert(@typeId(type) == Tid.Type); - assert(@typeId(void) == Tid.Void); - assert(@typeId(bool) == Tid.Bool); - assert(@typeId(noreturn) == Tid.NoReturn); - assert(@typeId(i8) == Tid.Int); - assert(@typeId(u8) == Tid.Int); - assert(@typeId(i64) == Tid.Int); - assert(@typeId(u64) == Tid.Int); - assert(@typeId(f32) == Tid.Float); - assert(@typeId(f64) == Tid.Float); - assert(@typeId(*f32) == Tid.Pointer); - assert(@typeId([2]u8) == Tid.Array); - assert(@typeId(AStruct) == Tid.Struct); - assert(@typeId(@typeOf(1)) == Tid.ComptimeInt); - assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); - assert(@typeId(@typeOf(undefined)) == Tid.Undefined); - assert(@typeId(@typeOf(null)) == Tid.Null); - assert(@typeId(?i32) == Tid.Optional); - assert(@typeId(anyerror!i32) == Tid.ErrorUnion); - assert(@typeId(anyerror) == Tid.ErrorSet); - assert(@typeId(AnEnum) == Tid.Enum); - assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); - assert(@typeId(AUnionEnum) == Tid.Union); - assert(@typeId(AUnion) == Tid.Union); - assert(@typeId(fn () void) == Tid.Fn); - assert(@typeId(@typeOf(builtin)) == Tid.Namespace); + assertOrPanic(@typeId(type) == Tid.Type); + assertOrPanic(@typeId(void) == Tid.Void); + assertOrPanic(@typeId(bool) == Tid.Bool); + assertOrPanic(@typeId(noreturn) == Tid.NoReturn); + assertOrPanic(@typeId(i8) == Tid.Int); + assertOrPanic(@typeId(u8) == Tid.Int); + assertOrPanic(@typeId(i64) == Tid.Int); + assertOrPanic(@typeId(u64) == Tid.Int); + assertOrPanic(@typeId(f32) == Tid.Float); + assertOrPanic(@typeId(f64) == Tid.Float); + assertOrPanic(@typeId(*f32) == Tid.Pointer); + assertOrPanic(@typeId([2]u8) == Tid.Array); + assertOrPanic(@typeId(AStruct) == Tid.Struct); + assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt); + assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); + assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined); + assertOrPanic(@typeId(@typeOf(null)) == Tid.Null); + assertOrPanic(@typeId(?i32) == Tid.Optional); + assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion); + assertOrPanic(@typeId(anyerror) == Tid.ErrorSet); + assertOrPanic(@typeId(AnEnum) == Tid.Enum); + assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); + assertOrPanic(@typeId(AUnionEnum) == Tid.Union); + assertOrPanic(@typeId(AUnion) == Tid.Union); + assertOrPanic(@typeId(fn () void) == Tid.Fn); + assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace); // TODO bound fn // TODO arg tuple // TODO opaque @@ -490,13 +485,13 @@ test "@typeName" { Unused, }; comptime { - assert(mem.eql(u8, @typeName(i64), "i64")); - assert(mem.eql(u8, @typeName(*usize), "*usize")); + assertOrPanic(mem.eql(u8, @typeName(i64), "i64")); + assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize")); // https://github.com/ziglang/zig/issues/675 - assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); - assert(mem.eql(u8, @typeName(Struct), "Struct")); - assert(mem.eql(u8, @typeName(Union), "Union")); - assert(mem.eql(u8, @typeName(Enum), "Enum")); + assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); + assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct")); + assertOrPanic(mem.eql(u8, @typeName(Union), "Union")); + assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum")); } } @@ -504,28 +499,16 @@ fn TypeFromFn(comptime T: type) type { return struct {}; } -test "volatile load and store" { - var number: i32 = 1234; - const ptr = (*volatile i32)(&number); - ptr.* += 1; - assert(ptr.* == 1235); +test "double implicit cast in same expression" { + var x = i32(u16(nine())); + assertOrPanic(x == 9); } - -test "slice string literal has type []const u8" { - comptime { - assert(@typeOf("aoeu"[0..]) == []const u8); - const array = []i32{ - 1, - 2, - 3, - 4, - }; - assert(@typeOf(array[0..]) == []const i32); - } +fn nine() u8 { + return 9; } test "global variable initialized to global variable array element" { - assert(global_ptr == &gdt[0]); + assertOrPanic(global_ptr == &gdt[0]); } const GDTEntry = struct { field: i32, @@ -543,16 +526,12 @@ export fn writeToVRam() void { vram[0] = 'X'; } -test "pointer child field" { - assert((*u32).Child == u32); -} - const OpaqueA = @OpaqueType(); const OpaqueB = @OpaqueType(); test "@OpaqueType" { - assert(*OpaqueA != *OpaqueB); - assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); - assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); + assertOrPanic(*OpaqueA != *OpaqueB); + assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); + assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); } test "variable is allowed to be a pointer to an opaque type" { @@ -581,25 +560,6 @@ test "implicit comptime while" { } } -test "struct inside function" { - testStructInFn(); - comptime testStructInFn(); -} - -fn testStructInFn() void { - const BlockKind = u32; - - const Block = struct { - kind: BlockKind, - }; - - var block = Block{ .kind = 1234 }; - - block.kind += 1; - - assert(block.kind == 1235); -} - fn fnThatClosesOverLocalConst() type { const c = 1; return struct { @@ -611,7 +571,7 @@ fn fnThatClosesOverLocalConst() type { test "function closes over local const" { const x = fnThatClosesOverLocalConst().g(); - assert(x == 1); + assertOrPanic(x == 1); } test "cold function" { @@ -648,21 +608,21 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: Pack test "slicing zero length array" { const s1 = ""[0..]; const s2 = ([]u32{})[0..]; - assert(s1.len == 0); - assert(s2.len == 0); - assert(mem.eql(u8, s1, "")); - assert(mem.eql(u32, s2, []u32{})); + assertOrPanic(s1.len == 0); + assertOrPanic(s2.len == 0); + assertOrPanic(mem.eql(u8, s1, "")); + assertOrPanic(mem.eql(u32, s2, []u32{})); } const addr1 = @ptrCast(*const u8, emptyFn); test "comptime cast fn to ptr" { const addr2 = @ptrCast(*const u8, emptyFn); - comptime assert(addr1 == addr2); + comptime assertOrPanic(addr1 == addr2); } test "equality compare fn ptrs" { var a = emptyFn; - assert(a == a); + assertOrPanic(a == a); } test "self reference through fn ptr field" { @@ -677,5 +637,51 @@ test "self reference through fn ptr field" { }; var a: S.A = undefined; a.f = S.foo; - assert(a.f(a) == 12); + assertOrPanic(a.f(a) == 12); +} + +test "volatile load and store" { + var number: i32 = 1234; + const ptr = (*volatile i32)(&number); + ptr.* += 1; + assertOrPanic(ptr.* == 1235); +} + +test "slice string literal has type []const u8" { + comptime { + assertOrPanic(@typeOf("aoeu"[0..]) == []const u8); + const array = []i32{ 1, 2, 3, 4 }; + assertOrPanic(@typeOf(array[0..]) == []const i32); + } +} + +test "pointer child field" { + assertOrPanic((*u32).Child == u32); +} + +test "struct inside function" { + testStructInFn(); + comptime testStructInFn(); +} + +fn testStructInFn() void { + const BlockKind = u32; + + const Block = struct { + kind: BlockKind, + }; + + var block = Block{ .kind = 1234 }; + + block.kind += 1; + + assertOrPanic(block.kind == 1235); +} + +test "fn call returning scalar optional in equality expression" { + assertOrPanic(getNull() == null); +} + +fn getNull() ?*i32 { + return null; } diff --git a/test/cases/namespace_depends_on_compile_var/a.zig b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig similarity index 100% rename from test/cases/namespace_depends_on_compile_var/a.zig rename to test/stage1/behavior/namespace_depends_on_compile_var/a.zig diff --git a/test/cases/namespace_depends_on_compile_var/b.zig b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig similarity index 100% rename from test/cases/namespace_depends_on_compile_var/b.zig rename to test/stage1/behavior/namespace_depends_on_compile_var/b.zig diff --git a/test/cases/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig similarity index 62% rename from test/cases/namespace_depends_on_compile_var/index.zig rename to test/stage1/behavior/namespace_depends_on_compile_var/index.zig index ccc49d9367..fe3e0cc020 100644 --- a/test/cases/namespace_depends_on_compile_var/index.zig +++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig @@ -1,11 +1,11 @@ const builtin = @import("builtin"); -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "namespace depends on compile var" { if (some_namespace.a_bool) { - assert(some_namespace.a_bool); + assertOrPanic(some_namespace.a_bool); } else { - assert(!some_namespace.a_bool); + assertOrPanic(!some_namespace.a_bool); } } const some_namespace = switch (builtin.os) { diff --git a/test/cases/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig similarity index 72% rename from test/cases/new_stack_call.zig rename to test/stage1/behavior/new_stack_call.zig index 5912550d54..b9ae2d27cd 100644 --- a/test/cases/new_stack_call.zig +++ b/test/stage1/behavior/new_stack_call.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; var new_stack_bytes: [1024]u8 = undefined; @@ -10,17 +10,17 @@ test "calling a function with a new stack" { const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); _ = targetFunction(arg); - assert(arg == 1234); - assert(a < b); + assertOrPanic(arg == 1234); + assertOrPanic(a < b); } fn targetFunction(x: i32) usize { - assert(x == 1234); + assertOrPanic(x == 1234); var local_variable: i32 = 42; const ptr = &local_variable; ptr.* += 1; - assert(local_variable == 43); + assertOrPanic(local_variable == 43); return @ptrToInt(ptr); } diff --git a/test/cases/null.zig b/test/stage1/behavior/null.zig similarity index 80% rename from test/cases/null.zig rename to test/stage1/behavior/null.zig index 825db88b1e..e2f86a05ba 100644 --- a/test/cases/null.zig +++ b/test/stage1/behavior/null.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "optional type" { const x: ?bool = true; @@ -17,13 +17,13 @@ test "optional type" { const z = next_x orelse 1234; - assert(z == 1234); + assertOrPanic(z == 1234); const final_x: ?i32 = 13; const num = final_x orelse unreachable; - assert(num == 13); + assertOrPanic(num == 13); } test "test maybe object and get a pointer to the inner value" { @@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" { b.* = false; } - assert(maybe_bool.? == false); + assertOrPanic(maybe_bool.? == false); } test "rhs maybe unwrap return" { @@ -47,9 +47,9 @@ test "maybe return" { } fn maybeReturnImpl() void { - assert(foo(1235).?); + assertOrPanic(foo(1235).?); if (foo(null) != null) unreachable; - assert(!foo(1234).?); + assertOrPanic(!foo(1234).?); } fn foo(x: ?i32) ?bool { @@ -58,7 +58,7 @@ fn foo(x: ?i32) ?bool { } test "if var maybe pointer" { - assert(shouldBeAPlus1(Particle{ + assertOrPanic(shouldBeAPlus1(Particle{ .a = 14, .b = 1, .c = 1, @@ -84,10 +84,10 @@ const Particle = struct { test "null literal outside function" { const is_null = here_is_a_null_literal.context == null; - assert(is_null); + assertOrPanic(is_null); const is_non_null = here_is_a_null_literal.context != null; - assert(!is_non_null); + assertOrPanic(!is_non_null); } const SillyStruct = struct { context: ?i32, @@ -98,8 +98,8 @@ test "test null runtime" { testTestNullRuntime(null); } fn testTestNullRuntime(x: ?i32) void { - assert(x == null); - assert(!(x != null)); + assertOrPanic(x == null); + assertOrPanic(!(x != null)); } test "optional void" { @@ -108,8 +108,8 @@ test "optional void" { } fn optionalVoidImpl() void { - assert(bar(null) == null); - assert(bar({}) != null); + assertOrPanic(bar(null) == null); + assertOrPanic(bar({}) != null); } fn bar(x: ?void) ?void { @@ -133,7 +133,7 @@ test "unwrap optional which is field of global var" { } struct_with_optional.field = 1234; if (struct_with_optional.field) |payload| { - assert(payload == 1234); + assertOrPanic(payload == 1234); } else { unreachable; } @@ -141,13 +141,13 @@ test "unwrap optional which is field of global var" { test "null with default unwrap" { const x: i32 = null orelse 1; - assert(x == 1); + assertOrPanic(x == 1); } test "optional types" { comptime { const opt_type_struct = StructWithOptionalType{ .t = u8 }; - assert(opt_type_struct.t != null and opt_type_struct.t.? == u8); + assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8); } } @@ -158,5 +158,5 @@ const StructWithOptionalType = struct { test "optional pointer to 0 bit type null value at runtime" { const EmptyStruct = struct {}; var x: ?*EmptyStruct = null; - assert(x == null); + assertOrPanic(x == null); } diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig new file mode 100644 index 0000000000..14692cb1ea --- /dev/null +++ b/test/stage1/behavior/optional.zig @@ -0,0 +1,81 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +pub const EmptyStruct = struct {}; + +test "optional pointer to size zero struct" { + var e = EmptyStruct{}; + var o: ?*EmptyStruct = &e; + assertOrPanic(o != null); +} + +test "equality compare nullable pointers" { + testNullPtrsEql(); + comptime testNullPtrsEql(); +} + +fn testNullPtrsEql() void { + var number: i32 = 1234; + + var x: ?*i32 = null; + var y: ?*i32 = null; + assertOrPanic(x == y); + y = &number; + assertOrPanic(x != y); + assertOrPanic(x != &number); + assertOrPanic(&number != x); + x = &number; + assertOrPanic(x == y); + assertOrPanic(x == &number); + assertOrPanic(&number == x); +} + +test "address of unwrap optional" { + const S = struct { + const Foo = struct { + a: i32, + }; + + var global: ?Foo = null; + + pub fn getFoo() anyerror!*Foo { + return &global.?; + } + }; + S.global = S.Foo{ .a = 1234 }; + const foo = S.getFoo() catch unreachable; + assertOrPanic(foo.a == 1234); +} + +test "passing an optional integer as a parameter" { + const S = struct { + fn entry() bool { + var x: i32 = 1234; + return foo(x); + } + + fn foo(x: ?i32) bool { + return x.? == 1234; + } + }; + assertOrPanic(S.entry()); + comptime assertOrPanic(S.entry()); +} + +test "unwrap function call with optional pointer return value" { + const S = struct { + fn entry() void { + assertOrPanic(foo().?.* == 1234); + assertOrPanic(bar() == null); + } + const global: i32 = 1234; + fn foo() ?*const i32 { + return &global; + } + fn bar() ?*i32 { + return null; + } + }; + S.entry(); + // TODO https://github.com/ziglang/zig/issues/1901 + //comptime S.entry(); +} diff --git a/test/cases/pointers.zig b/test/stage1/behavior/pointers.zig similarity index 50% rename from test/cases/pointers.zig rename to test/stage1/behavior/pointers.zig index 47afb60a2e..1142d89ab5 100644 --- a/test/cases/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; test "dereference pointer" { comptime testDerefPtr(); @@ -10,33 +10,33 @@ fn testDerefPtr() void { var x: i32 = 1234; var y = &x; y.* += 1; - assert(x == 1235); + assertOrPanic(x == 1235); } test "pointer arithmetic" { var ptr = c"abcd"; - assert(ptr[0] == 'a'); + assertOrPanic(ptr[0] == 'a'); ptr += 1; - assert(ptr[0] == 'b'); + assertOrPanic(ptr[0] == 'b'); ptr += 1; - assert(ptr[0] == 'c'); + assertOrPanic(ptr[0] == 'c'); ptr += 1; - assert(ptr[0] == 'd'); + assertOrPanic(ptr[0] == 'd'); ptr += 1; - assert(ptr[0] == 0); + assertOrPanic(ptr[0] == 0); ptr -= 1; - assert(ptr[0] == 'd'); + assertOrPanic(ptr[0] == 'd'); ptr -= 1; - assert(ptr[0] == 'c'); + assertOrPanic(ptr[0] == 'c'); ptr -= 1; - assert(ptr[0] == 'b'); + assertOrPanic(ptr[0] == 'b'); ptr -= 1; - assert(ptr[0] == 'a'); + assertOrPanic(ptr[0] == 'a'); } test "double pointer parsing" { - comptime assert(PtrOf(PtrOf(i32)) == **i32); + comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32); } fn PtrOf(comptime T: type) type { diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig new file mode 100644 index 0000000000..f7f8bb523b --- /dev/null +++ b/test/stage1/behavior/popcount.zig @@ -0,0 +1,25 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@popCount" { + comptime testPopCount(); + testPopCount(); +} + +fn testPopCount() void { + { + var x: u32 = 0xaa; + assertOrPanic(@popCount(x) == 4); + } + { + var x: u32 = 0xaaaaaaaa; + assertOrPanic(@popCount(x) == 16); + } + { + var x: i16 = -1; + assertOrPanic(@popCount(x) == 16); + } + comptime { + assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); + } +} + diff --git a/test/cases/ptrcast.zig b/test/stage1/behavior/ptrcast.zig similarity index 100% rename from test/cases/ptrcast.zig rename to test/stage1/behavior/ptrcast.zig diff --git a/test/cases/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig similarity index 54% rename from test/cases/pub_enum/index.zig rename to test/stage1/behavior/pub_enum/index.zig index 7fdd07b8a3..181113f6bf 100644 --- a/test/cases/pub_enum/index.zig +++ b/test/stage1/behavior/pub_enum/index.zig @@ -1,13 +1,13 @@ const other = @import("other.zig"); -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "pub enum" { pubEnumTest(other.APubEnum.Two); } fn pubEnumTest(foo: other.APubEnum) void { - assert(foo == other.APubEnum.Two); + assertOrPanic(foo == other.APubEnum.Two); } test "cast with imported symbol" { - assert(other.size_t(42) == 42); + assertOrPanic(other.size_t(42) == 42); } diff --git a/test/cases/pub_enum/other.zig b/test/stage1/behavior/pub_enum/other.zig similarity index 100% rename from test/cases/pub_enum/other.zig rename to test/stage1/behavior/pub_enum/other.zig diff --git a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig similarity index 77% rename from test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig rename to test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig index 3c94bb0d49..acbe6b2459 100644 --- a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig +++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -1,14 +1,14 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const mem = @import("std").mem; var ok: bool = false; test "reference a variable in an if after an if in the 2nd switch prong" { foo(true, Num.Two, false, "aoeu"); - assert(!ok); + assertOrPanic(!ok); foo(false, Num.One, false, "aoeu"); - assert(!ok); + assertOrPanic(!ok); foo(true, Num.One, false, "aoeu"); - assert(ok); + assertOrPanic(ok); } const Num = enum { @@ -32,6 +32,6 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { } fn a(x: []const u8) void { - assert(mem.eql(u8, x, "aoeu")); + assertOrPanic(mem.eql(u8, x, "aoeu")); ok = true; } diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig new file mode 100644 index 0000000000..f4c142e0f7 --- /dev/null +++ b/test/stage1/behavior/reflection.zig @@ -0,0 +1,96 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; +const reflection = @This(); + +test "reflection: array, pointer, optional, error union type child" { + comptime { + assertOrPanic(([10]u8).Child == u8); + assertOrPanic((*u8).Child == u8); + assertOrPanic((anyerror!u8).Payload == u8); + assertOrPanic((?u8).Child == u8); + } +} + +test "reflection: function return type, var args, and param types" { + comptime { + assertOrPanic(@typeOf(dummy).ReturnType == i32); + assertOrPanic(!@typeOf(dummy).is_var_args); + assertOrPanic(@typeOf(dummy_varargs).is_var_args); + assertOrPanic(@typeOf(dummy).arg_count == 3); + assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool); + assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32); + assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32); + } +} + +fn dummy(a: bool, b: i32, c: f32) i32 { + return 1234; +} +fn dummy_varargs(args: ...) void {} + +test "reflection: struct member types and names" { + comptime { + assertOrPanic(@memberCount(Foo) == 3); + + assertOrPanic(@memberType(Foo, 0) == i32); + assertOrPanic(@memberType(Foo, 1) == bool); + assertOrPanic(@memberType(Foo, 2) == void); + + assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one")); + assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two")); + assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three")); + } +} + +test "reflection: enum member types and names" { + comptime { + assertOrPanic(@memberCount(Bar) == 4); + + assertOrPanic(@memberType(Bar, 0) == void); + assertOrPanic(@memberType(Bar, 1) == i32); + assertOrPanic(@memberType(Bar, 2) == bool); + assertOrPanic(@memberType(Bar, 3) == f64); + + assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four")); + } +} + +test "reflection: @field" { + var f = Foo{ + .one = 42, + .two = true, + .three = void{}, + }; + + assertOrPanic(f.one == f.one); + assertOrPanic(@field(f, "o" ++ "ne") == f.one); + assertOrPanic(@field(f, "t" ++ "wo") == f.two); + assertOrPanic(@field(f, "th" ++ "ree") == f.three); + assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant); + assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One); + assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two); + assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three); + assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four); + assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); + @field(f, "o" ++ "ne") = 4; + assertOrPanic(f.one == 4); +} + +const Foo = struct { + const constant = 52; + + one: i32, + two: bool, + three: void, +}; + +const Bar = union(enum) { + One: void, + Two: i32, + Three: bool, + Four: f64, +}; + diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig new file mode 100644 index 0000000000..ddaea4c242 --- /dev/null +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -0,0 +1,69 @@ +const builtin = @import("builtin"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@sizeOf and @typeOf" { + const y: @typeOf(x) = 120; + assertOrPanic(@sizeOf(@typeOf(y)) == 2); +} +const x: u16 = 13; +const z: @typeOf(x) = 19; + +const A = struct { + a: u8, + b: u32, + c: u8, + d: u3, + e: u5, + f: u16, + g: u16, +}; + +const P = packed struct { + a: u8, + b: u32, + c: u8, + d: u3, + e: u5, + f: u16, + g: u16, +}; + +test "@byteOffsetOf" { + // Packed structs have fixed memory layout + assertOrPanic(@byteOffsetOf(P, "a") == 0); + assertOrPanic(@byteOffsetOf(P, "b") == 1); + assertOrPanic(@byteOffsetOf(P, "c") == 5); + assertOrPanic(@byteOffsetOf(P, "d") == 6); + assertOrPanic(@byteOffsetOf(P, "e") == 6); + assertOrPanic(@byteOffsetOf(P, "f") == 7); + assertOrPanic(@byteOffsetOf(P, "g") == 9); + + // Normal struct fields can be moved/padded + var a: A = undefined; + assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); + assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); + assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); + assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); + assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); + assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); + assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); +} + +test "@bitOffsetOf" { + // Packed structs have fixed memory layout + assertOrPanic(@bitOffsetOf(P, "a") == 0); + assertOrPanic(@bitOffsetOf(P, "b") == 8); + assertOrPanic(@bitOffsetOf(P, "c") == 40); + assertOrPanic(@bitOffsetOf(P, "d") == 48); + assertOrPanic(@bitOffsetOf(P, "e") == 51); + assertOrPanic(@bitOffsetOf(P, "f") == 56); + assertOrPanic(@bitOffsetOf(P, "g") == 72); + + assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); + assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); + assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); + assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); + assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); + assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); + assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); +} diff --git a/test/cases/slice.zig b/test/stage1/behavior/slice.zig similarity index 62% rename from test/cases/slice.zig rename to test/stage1/behavior/slice.zig index b4b43bdd19..cc29e43485 100644 --- a/test/cases/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -1,20 +1,20 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const mem = @import("std").mem; const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { - assert(@ptrToInt(x.ptr) == 0x1000); - assert(x.len == 0x500); + assertOrPanic(@ptrToInt(x.ptr) == 0x1000); + assertOrPanic(x.len == 0x500); - assert(@ptrToInt(y.ptr) == 0x1100); - assert(y.len == 0x400); + assertOrPanic(@ptrToInt(y.ptr) == 0x1100); + assertOrPanic(y.len == 0x400); } test "slice child property" { var array: [5]i32 = undefined; var slice = array[0..]; - assert(@typeOf(slice).Child == i32); + assertOrPanic(@typeOf(slice).Child == i32); } test "runtime safety lets us slice from len..len" { @@ -23,7 +23,7 @@ test "runtime safety lets us slice from len..len" { 2, 3, }; - assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); + assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); } fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { @@ -36,5 +36,5 @@ test "implicitly cast array of size 0 to slice" { } fn assertLenIsZero(msg: []const u8) void { - assert(msg.len == 0); + assertOrPanic(msg.len == 0); } diff --git a/test/cases/struct.zig b/test/stage1/behavior/struct.zig similarity index 64% rename from test/cases/struct.zig rename to test/stage1/behavior/struct.zig index bbbd21912c..92ae2baa15 100644 --- a/test/cases/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -12,7 +12,7 @@ const empty_global_instance = StructWithNoFields{}; test "call struct static method" { const result = StructWithNoFields.add(3, 4); - assert(result == 7); + assertOrPanic(result == 7); } test "return empty struct instance" { @@ -24,8 +24,8 @@ fn returnEmptyStructInstance() StructWithNoFields { const should_be_11 = StructWithNoFields.add(5, 6); -test "invake static method in global scope" { - assert(should_be_11 == 11); +test "invoke static method in global scope" { + assertOrPanic(should_be_11 == 11); } test "void struct fields" { @@ -34,8 +34,8 @@ test "void struct fields" { .b = 1, .c = void{}, }; - assert(foo.b == 1); - assert(@sizeOf(VoidStructFieldsFoo) == 4); + assertOrPanic(foo.b == 1); + assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4); } const VoidStructFieldsFoo = struct { a: void, @@ -50,7 +50,7 @@ test "structs" { foo.b = foo.a == 1; testFoo(foo); testMutation(&foo); - assert(foo.c == 100); + assertOrPanic(foo.c == 100); } const StructFoo = struct { a: i32, @@ -58,7 +58,7 @@ const StructFoo = struct { c: f32, }; fn testFoo(foo: StructFoo) void { - assert(foo.b); + assertOrPanic(foo.b); } fn testMutation(foo: *StructFoo) void { foo.c = 100; @@ -83,7 +83,7 @@ test "struct point to self" { root.next = &node; - assert(node.next.next.next.val.x == 1); + assertOrPanic(node.next.next.next.val.x == 1); } test "struct byval assign" { @@ -92,18 +92,18 @@ test "struct byval assign" { foo1.a = 1234; foo2.a = 0; - assert(foo2.a == 0); + assertOrPanic(foo2.a == 0); foo2 = foo1; - assert(foo2.a == 1234); + assertOrPanic(foo2.a == 1234); } fn structInitializer() void { const val = Val{ .x = 42 }; - assert(val.x == 42); + assertOrPanic(val.x == 42); } test "fn call of struct field" { - assert(callStructField(Foo{ .ptr = aFunc }) == 13); + assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13); } const Foo = struct { @@ -122,7 +122,7 @@ test "store member function in variable" { const instance = MemberFnTestFoo{ .x = 1234 }; const memberFn = MemberFnTestFoo.member; const result = memberFn(instance); - assert(result == 1234); + assertOrPanic(result == 1234); } const MemberFnTestFoo = struct { x: i32, @@ -134,12 +134,12 @@ const MemberFnTestFoo = struct { test "call member function directly" { const instance = MemberFnTestFoo{ .x = 1234 }; const result = MemberFnTestFoo.member(instance); - assert(result == 1234); + assertOrPanic(result == 1234); } test "member functions" { const r = MemberFnRand{ .seed = 1234 }; - assert(r.getSeed() == 1234); + assertOrPanic(r.getSeed() == 1234); } const MemberFnRand = struct { seed: u32, @@ -150,7 +150,7 @@ const MemberFnRand = struct { test "return struct byval from function" { const bar = makeBar(1234, 5678); - assert(bar.y == 5678); + assertOrPanic(bar.y == 5678); } const Bar = struct { x: i32, @@ -165,7 +165,7 @@ fn makeBar(x: i32, y: i32) Bar { test "empty struct method call" { const es = EmptyStruct{}; - assert(es.method() == 1234); + assertOrPanic(es.method() == 1234); } const EmptyStruct = struct { fn method(es: *const EmptyStruct) i32 { @@ -182,7 +182,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 { } test "pass slice of empty struct to fn" { - assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); + assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); } fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { return slice.len; @@ -200,7 +200,7 @@ test "packed struct" { }; foo.y += 1; const four = foo.x + foo.y; - assert(four == 4); + assertOrPanic(four == 4); } const BitField1 = packed struct { @@ -217,17 +217,17 @@ const bit_field_1 = BitField1{ test "bit field access" { var data = bit_field_1; - assert(getA(&data) == 1); - assert(getB(&data) == 2); - assert(getC(&data) == 3); - comptime assert(@sizeOf(BitField1) == 1); + assertOrPanic(getA(&data) == 1); + assertOrPanic(getB(&data) == 2); + assertOrPanic(getC(&data) == 3); + comptime assertOrPanic(@sizeOf(BitField1) == 1); data.b += 1; - assert(data.b == 3); + assertOrPanic(data.b == 3); data.a += 1; - assert(data.a == 2); - assert(data.b == 3); + assertOrPanic(data.a == 2); + assertOrPanic(data.b == 3); } fn getA(data: *const BitField1) u3 { @@ -254,8 +254,8 @@ const Foo96Bits = packed struct { test "packed struct 24bits" { comptime { - assert(@sizeOf(Foo24Bits) == 3); - assert(@sizeOf(Foo96Bits) == 12); + assertOrPanic(@sizeOf(Foo24Bits) == 3); + assertOrPanic(@sizeOf(Foo96Bits) == 12); } var value = Foo96Bits{ @@ -265,28 +265,28 @@ test "packed struct 24bits" { .d = 0, }; value.a += 1; - assert(value.a == 1); - assert(value.b == 0); - assert(value.c == 0); - assert(value.d == 0); + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 0); + assertOrPanic(value.c == 0); + assertOrPanic(value.d == 0); value.b += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 0); - assert(value.d == 0); + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 0); + assertOrPanic(value.d == 0); value.c += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 1); - assert(value.d == 0); + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 1); + assertOrPanic(value.d == 0); value.d += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 1); - assert(value.d == 1); + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 1); + assertOrPanic(value.d == 1); } const FooArray24Bits = packed struct { @@ -297,43 +297,43 @@ const FooArray24Bits = packed struct { test "packed array 24bits" { comptime { - assert(@sizeOf([9]Foo24Bits) == 9 * 3); - assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); + assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3); + assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); } var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); bytes[bytes.len - 1] = 0xaa; const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; - assert(ptr.a == 0); - assert(ptr.b[0].field == 0); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); + assertOrPanic(ptr.a == 0); + assertOrPanic(ptr.b[0].field == 0); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); ptr.a = maxInt(u16); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == 0); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == 0); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); ptr.b[0].field = maxInt(u24); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); ptr.b[1].field = maxInt(u24); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == maxInt(u24)); - assert(ptr.c == 0); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == maxInt(u24)); + assertOrPanic(ptr.c == 0); ptr.c = maxInt(u16); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == maxInt(u24)); - assert(ptr.c == maxInt(u16)); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == maxInt(u24)); + assertOrPanic(ptr.c == maxInt(u16)); - assert(bytes[bytes.len - 1] == 0xaa); + assertOrPanic(bytes[bytes.len - 1] == 0xaa); } const FooStructAligned = packed struct { @@ -347,17 +347,17 @@ const FooArrayOfAligned = packed struct { test "aligned array of packed struct" { comptime { - assert(@sizeOf(FooStructAligned) == 2); - assert(@sizeOf(FooArrayOfAligned) == 2 * 2); + assertOrPanic(@sizeOf(FooStructAligned) == 2); + assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2); } var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; - assert(ptr.a[0].a == 0xbb); - assert(ptr.a[0].b == 0xbb); - assert(ptr.a[1].a == 0xbb); - assert(ptr.a[1].b == 0xbb); + assertOrPanic(ptr.a[0].a == 0xbb); + assertOrPanic(ptr.a[0].b == 0xbb); + assertOrPanic(ptr.a[1].a == 0xbb); + assertOrPanic(ptr.a[1].b == 0xbb); } test "runtime struct initialization of bitfield" { @@ -370,10 +370,10 @@ test "runtime struct initialization of bitfield" { .y = @intCast(u4, x2), }; - assert(s1.x == x1); - assert(s1.y == x1); - assert(s2.x == @intCast(u4, x2)); - assert(s2.y == @intCast(u4, x2)); + assertOrPanic(s1.x == x1); + assertOrPanic(s1.y == x1); + assertOrPanic(s2.x == @intCast(u4, x2)); + assertOrPanic(s2.y == @intCast(u4, x2)); } var x1 = u4(1); @@ -400,18 +400,18 @@ test "native bit field understands endianness" { @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; - assert(bitfields.f1 == 0x1111); - assert(bitfields.f2 == 0x2222); - assert(bitfields.f3 == 0x33); - assert(bitfields.f4 == 0x44); - assert(bitfields.f5 == 0x5); - assert(bitfields.f6 == 0x6); - assert(bitfields.f7 == 0x77); + assertOrPanic(bitfields.f1 == 0x1111); + assertOrPanic(bitfields.f2 == 0x2222); + assertOrPanic(bitfields.f3 == 0x33); + assertOrPanic(bitfields.f4 == 0x44); + assertOrPanic(bitfields.f5 == 0x5); + assertOrPanic(bitfields.f6 == 0x6); + assertOrPanic(bitfields.f7 == 0x77); } test "align 1 field before self referential align 8 field as slice return type" { const result = alloc(Expr); - assert(result.len == 0); + assertOrPanic(result.len == 0); } const Expr = union(enum) { @@ -434,10 +434,10 @@ test "call method with mutable reference to struct with no fields" { }; var s = S{}; - assert(S.doC(&s)); - assert(s.doC()); - assert(S.do(&s)); - assert(s.do()); + assertOrPanic(S.doC(&s)); + assertOrPanic(s.doC()); + assertOrPanic(S.do(&s)); + assertOrPanic(s.do()); } test "implicit cast packed struct field to const ptr" { @@ -453,7 +453,7 @@ test "implicit cast packed struct field to const ptr" { var lup: LevelUpMove = undefined; lup.level = 12; const res = LevelUpMove.toInt(lup.level); - assert(res == 12); + assertOrPanic(res == 12); } test "pointer to packed struct member in a stack variable" { @@ -464,7 +464,7 @@ test "pointer to packed struct member in a stack variable" { var s = S{ .a = 2, .b = 0 }; var b_ptr = &s.b; - assert(s.b == 0); + assertOrPanic(s.b == 0); b_ptr.* = 2; - assert(s.b == 2); + assertOrPanic(s.b == 2); } diff --git a/test/cases/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig similarity index 81% rename from test/cases/struct_contains_null_ptr_itself.zig rename to test/stage1/behavior/struct_contains_null_ptr_itself.zig index 21175974b3..4cc479f31c 100644 --- a/test/cases/struct_contains_null_ptr_itself.zig +++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; test "struct contains null pointer which contains original struct" { var x: ?*NodeLineComment = null; - assert(x == null); + assertOrPanic(x == null); } pub const Node = struct { diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig similarity index 68% rename from test/cases/struct_contains_slice_of_itself.zig rename to test/stage1/behavior/struct_contains_slice_of_itself.zig index aa3075312c..15780a7c44 100644 --- a/test/cases/struct_contains_slice_of_itself.zig +++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const Node = struct { payload: i32, @@ -39,12 +39,12 @@ test "struct contains slice of itself" { .payload = 1234, .children = nodes[0..], }; - assert(root.payload == 1234); - assert(root.children[0].payload == 1); - assert(root.children[1].payload == 2); - assert(root.children[2].payload == 3); - assert(root.children[2].children[0].payload == 31); - assert(root.children[2].children[1].payload == 32); + assertOrPanic(root.payload == 1234); + assertOrPanic(root.children[0].payload == 1); + assertOrPanic(root.children[1].payload == 2); + assertOrPanic(root.children[2].payload == 3); + assertOrPanic(root.children[2].children[0].payload == 31); + assertOrPanic(root.children[2].children[1].payload == 32); } test "struct contains aligned slice of itself" { @@ -76,10 +76,10 @@ test "struct contains aligned slice of itself" { .payload = 1234, .children = nodes[0..], }; - assert(root.payload == 1234); - assert(root.children[0].payload == 1); - assert(root.children[1].payload == 2); - assert(root.children[2].payload == 3); - assert(root.children[2].children[0].payload == 31); - assert(root.children[2].children[1].payload == 32); + assertOrPanic(root.payload == 1234); + assertOrPanic(root.children[0].payload == 1); + assertOrPanic(root.children[1].payload == 2); + assertOrPanic(root.children[2].payload == 3); + assertOrPanic(root.children[2].children[0].payload == 31); + assertOrPanic(root.children[2].children[1].payload == 32); } diff --git a/test/cases/switch.zig b/test/stage1/behavior/switch.zig similarity index 72% rename from test/cases/switch.zig rename to test/stage1/behavior/switch.zig index 1162fdd4b2..4ac971397e 100644 --- a/test/cases/switch.zig +++ b/test/stage1/behavior/switch.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "switch with numbers" { testSwitchWithNumbers(13); @@ -10,14 +10,14 @@ fn testSwitchWithNumbers(x: u32) void { 13 => true, else => false, }; - assert(result); + assertOrPanic(result); } test "switch with all ranges" { - assert(testSwitchWithAllRanges(50, 3) == 1); - assert(testSwitchWithAllRanges(101, 0) == 2); - assert(testSwitchWithAllRanges(300, 5) == 3); - assert(testSwitchWithAllRanges(301, 6) == 6); + assertOrPanic(testSwitchWithAllRanges(50, 3) == 1); + assertOrPanic(testSwitchWithAllRanges(101, 0) == 2); + assertOrPanic(testSwitchWithAllRanges(300, 5) == 3); + assertOrPanic(testSwitchWithAllRanges(301, 6) == 6); } fn testSwitchWithAllRanges(x: u32, y: u32) u32 { @@ -40,7 +40,7 @@ test "implicit comptime switch" { }; comptime { - assert(result + 1 == 14); + assertOrPanic(result + 1 == 14); } } @@ -71,7 +71,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) void { SwitchStatmentFoo.C => 3, SwitchStatmentFoo.D => 4, }; - assert(val == 3); + assertOrPanic(val == 3); } const SwitchStatmentFoo = enum { A, @@ -93,10 +93,10 @@ const SwitchProngWithVarEnum = union(enum) { fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { switch (a) { SwitchProngWithVarEnum.One => |x| { - assert(x == 13); + assertOrPanic(x == 13); }, SwitchProngWithVarEnum.Two => |x| { - assert(x == 13.0); + assertOrPanic(x == 13.0); }, SwitchProngWithVarEnum.Meh => |x| { const v: void = x; @@ -116,7 +116,7 @@ fn testSwitchEnumPtrCapture() void { else => unreachable, } switch (value) { - SwitchProngWithVarEnum.One => |x| assert(x == 1235), + SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235), else => unreachable, } } @@ -127,7 +127,7 @@ test "switch with multiple expressions" { 4, 5, 6 => 2, else => i32(3), }; - assert(x == 2); + assertOrPanic(x == 2); } fn returnsFive() i32 { return 5; @@ -149,12 +149,12 @@ fn returnsFalse() bool { } } test "switch on const enum with var" { - assert(!returnsFalse()); + assertOrPanic(!returnsFalse()); } test "switch on type" { - assert(trueIfBoolFalseOtherwise(bool)); - assert(!trueIfBoolFalseOtherwise(i32)); + assertOrPanic(trueIfBoolFalseOtherwise(bool)); + assertOrPanic(!trueIfBoolFalseOtherwise(i32)); } fn trueIfBoolFalseOtherwise(comptime T: type) bool { @@ -170,16 +170,16 @@ test "switch handles all cases of number" { } fn testSwitchHandleAllCases() void { - assert(testSwitchHandleAllCasesExhaustive(0) == 3); - assert(testSwitchHandleAllCasesExhaustive(1) == 2); - assert(testSwitchHandleAllCasesExhaustive(2) == 1); - assert(testSwitchHandleAllCasesExhaustive(3) == 0); + assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3); + assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2); + assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1); + assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0); - assert(testSwitchHandleAllCasesRange(100) == 0); - assert(testSwitchHandleAllCasesRange(200) == 1); - assert(testSwitchHandleAllCasesRange(201) == 2); - assert(testSwitchHandleAllCasesRange(202) == 4); - assert(testSwitchHandleAllCasesRange(230) == 3); + assertOrPanic(testSwitchHandleAllCasesRange(100) == 0); + assertOrPanic(testSwitchHandleAllCasesRange(200) == 1); + assertOrPanic(testSwitchHandleAllCasesRange(201) == 2); + assertOrPanic(testSwitchHandleAllCasesRange(202) == 4); + assertOrPanic(testSwitchHandleAllCasesRange(230) == 3); } fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { @@ -207,8 +207,8 @@ test "switch all prongs unreachable" { } fn testAllProngsUnreachable() void { - assert(switchWithUnreachable(1) == 2); - assert(switchWithUnreachable(2) == 10); + assertOrPanic(switchWithUnreachable(1) == 2); + assertOrPanic(switchWithUnreachable(2) == 10); } fn switchWithUnreachable(x: i32) i32 { @@ -230,7 +230,7 @@ test "capture value of switch with all unreachable prongs" { const x = return_a_number() catch |err| switch (err) { else => unreachable, }; - assert(x == 1); + assertOrPanic(x == 1); } test "switching on booleans" { @@ -239,14 +239,14 @@ test "switching on booleans" { } fn testSwitchOnBools() void { - assert(testSwitchOnBoolsTrueAndFalse(true) == false); - assert(testSwitchOnBoolsTrueAndFalse(false) == true); + assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false); + assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true); - assert(testSwitchOnBoolsTrueWithElse(true) == false); - assert(testSwitchOnBoolsTrueWithElse(false) == true); + assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false); + assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true); - assert(testSwitchOnBoolsFalseWithElse(true) == false); - assert(testSwitchOnBoolsFalseWithElse(false) == true); + assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false); + assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true); } fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { diff --git a/test/cases/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig similarity index 79% rename from test/cases/switch_prong_err_enum.zig rename to test/stage1/behavior/switch_prong_err_enum.zig index 89060690fc..6ac1919f0d 100644 --- a/test/cases/switch_prong_err_enum.zig +++ b/test/stage1/behavior/switch_prong_err_enum.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; var read_count: u64 = 0; @@ -22,9 +22,9 @@ fn doThing(form_id: u64) anyerror!FormValue { test "switch prong returns error enum" { switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { - assert(payload == 1); + assertOrPanic(payload == 1); }, else => unreachable, } - assert(read_count == 1); + assertOrPanic(read_count == 1); } diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig similarity index 82% rename from test/cases/switch_prong_implicit_cast.zig rename to test/stage1/behavior/switch_prong_implicit_cast.zig index 56d37e290f..4ca031e2e1 100644 --- a/test/cases/switch_prong_implicit_cast.zig +++ b/test/stage1/behavior/switch_prong_implicit_cast.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const FormValue = union(enum) { One: void, @@ -18,5 +18,5 @@ test "switch prong implicit cast" { FormValue.One => false, FormValue.Two => |x| x, }; - assert(result); + assertOrPanic(result); } diff --git a/test/cases/syntax.zig b/test/stage1/behavior/syntax.zig similarity index 99% rename from test/cases/syntax.zig rename to test/stage1/behavior/syntax.zig index 0c8c3c5ed3..451e396142 100644 --- a/test/cases/syntax.zig +++ b/test/stage1/behavior/syntax.zig @@ -57,3 +57,4 @@ fn asm_lists() void { :::"a","b",); } } + diff --git a/test/cases/this.zig b/test/stage1/behavior/this.zig similarity index 74% rename from test/cases/this.zig rename to test/stage1/behavior/this.zig index c7be074f36..0e3a7a03ae 100644 --- a/test/cases/this.zig +++ b/test/stage1/behavior/this.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const module = @This(); @@ -20,7 +20,7 @@ fn add(x: i32, y: i32) i32 { } test "this refer to module call private fn" { - assert(module.add(1, 2) == 3); + assertOrPanic(module.add(1, 2) == 3); } test "this refer to container" { @@ -29,6 +29,7 @@ test "this refer to container" { .y = 34, }; pt.addOne(); - assert(pt.x == 13); - assert(pt.y == 35); + assertOrPanic(pt.x == 13); + assertOrPanic(pt.y == 35); } + diff --git a/test/cases/truncate.zig b/test/stage1/behavior/truncate.zig similarity index 65% rename from test/cases/truncate.zig rename to test/stage1/behavior/truncate.zig index 02b5085ccd..b7904bc7fb 100644 --- a/test/cases/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -1,8 +1,8 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; test "truncate u0 to larger integer allowed and has comptime known result" { var x: u0 = 0; const y = @truncate(u8, x); - comptime assert(y == 0); + comptime assertOrPanic(y == 0); } diff --git a/test/cases/try.zig b/test/stage1/behavior/try.zig similarity index 79% rename from test/cases/try.zig rename to test/stage1/behavior/try.zig index 450a9af6ac..ed48875eb4 100644 --- a/test/cases/try.zig +++ b/test/stage1/behavior/try.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "try on error union" { tryOnErrorUnionImpl(); @@ -11,7 +11,7 @@ fn tryOnErrorUnionImpl() void { error.CrappedOut => i32(2), else => unreachable, }; - assert(x == 11); + assertOrPanic(x == 11); } fn returnsTen() anyerror!i32 { @@ -20,10 +20,10 @@ fn returnsTen() anyerror!i32 { test "try without vars" { const result1 = if (failIfTrue(true)) 1 else |_| i32(2); - assert(result1 == 2); + assertOrPanic(result1 == 2); const result2 = if (failIfTrue(false)) 1 else |_| i32(2); - assert(result2 == 1); + assertOrPanic(result2 == 1); } fn failIfTrue(ok: bool) anyerror!void { @@ -38,6 +38,6 @@ test "try then not executed with assignment" { if (failIfTrue(true)) { unreachable; } else |err| { - assert(err == error.ItBroke); + assertOrPanic(err == error.ItBroke); } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig new file mode 100644 index 0000000000..5ad80e06e1 --- /dev/null +++ b/test/stage1/behavior/type_info.zig @@ -0,0 +1,264 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; +const TypeInfo = @import("builtin").TypeInfo; +const TypeId = @import("builtin").TypeId; + +test "type info: tag type, void info" { + testBasic(); + comptime testBasic(); +} + +fn testBasic() void { + assertOrPanic(@TagType(TypeInfo) == TypeId); + const void_info = @typeInfo(void); + assertOrPanic(TypeId(void_info) == TypeId.Void); + assertOrPanic(void_info.Void == {}); +} + +test "type info: integer, floating point type info" { + testIntFloat(); + comptime testIntFloat(); +} + +fn testIntFloat() void { + const u8_info = @typeInfo(u8); + assertOrPanic(TypeId(u8_info) == TypeId.Int); + assertOrPanic(!u8_info.Int.is_signed); + assertOrPanic(u8_info.Int.bits == 8); + + const f64_info = @typeInfo(f64); + assertOrPanic(TypeId(f64_info) == TypeId.Float); + assertOrPanic(f64_info.Float.bits == 64); +} + +test "type info: pointer type info" { + testPointer(); + comptime testPointer(); +} + +fn testPointer() void { + const u32_ptr_info = @typeInfo(*u32); + assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); + assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); + assertOrPanic(u32_ptr_info.Pointer.is_const == false); + assertOrPanic(u32_ptr_info.Pointer.is_volatile == false); + assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32)); + assertOrPanic(u32_ptr_info.Pointer.child == u32); +} + +test "type info: unknown length pointer type info" { + testUnknownLenPtr(); + comptime testUnknownLenPtr(); +} + +fn testUnknownLenPtr() void { + const u32_ptr_info = @typeInfo([*]const volatile f64); + assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); + assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); + assertOrPanic(u32_ptr_info.Pointer.is_const == true); + assertOrPanic(u32_ptr_info.Pointer.is_volatile == true); + assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64)); + assertOrPanic(u32_ptr_info.Pointer.child == f64); +} + +test "type info: slice type info" { + testSlice(); + comptime testSlice(); +} + +fn testSlice() void { + const u32_slice_info = @typeInfo([]u32); + assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer); + assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); + assertOrPanic(u32_slice_info.Pointer.is_const == false); + assertOrPanic(u32_slice_info.Pointer.is_volatile == false); + assertOrPanic(u32_slice_info.Pointer.alignment == 4); + assertOrPanic(u32_slice_info.Pointer.child == u32); +} + +test "type info: array type info" { + testArray(); + comptime testArray(); +} + +fn testArray() void { + const arr_info = @typeInfo([42]bool); + assertOrPanic(TypeId(arr_info) == TypeId.Array); + assertOrPanic(arr_info.Array.len == 42); + assertOrPanic(arr_info.Array.child == bool); +} + +test "type info: optional type info" { + testOptional(); + comptime testOptional(); +} + +fn testOptional() void { + const null_info = @typeInfo(?void); + assertOrPanic(TypeId(null_info) == TypeId.Optional); + assertOrPanic(null_info.Optional.child == void); +} + +test "type info: promise info" { + testPromise(); + comptime testPromise(); +} + +fn testPromise() void { + const null_promise_info = @typeInfo(promise); + assertOrPanic(TypeId(null_promise_info) == TypeId.Promise); + assertOrPanic(null_promise_info.Promise.child == null); + + const promise_info = @typeInfo(promise->usize); + assertOrPanic(TypeId(promise_info) == TypeId.Promise); + assertOrPanic(promise_info.Promise.child.? == usize); +} + +test "type info: error set, error union info" { + testErrorSet(); + comptime testErrorSet(); +} + +fn testErrorSet() void { + const TestErrorSet = error{ + First, + Second, + Third, + }; + + const error_set_info = @typeInfo(TestErrorSet); + assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet); + assertOrPanic(error_set_info.ErrorSet.errors.len == 3); + assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); + assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); + + const error_union_info = @typeInfo(TestErrorSet!usize); + assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion); + assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet); + assertOrPanic(error_union_info.ErrorUnion.payload == usize); +} + +test "type info: enum info" { + testEnum(); + comptime testEnum(); +} + +fn testEnum() void { + const Os = enum { + Windows, + Macos, + Linux, + FreeBSD, + }; + + const os_info = @typeInfo(Os); + assertOrPanic(TypeId(os_info) == TypeId.Enum); + assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(os_info.Enum.fields.len == 4); + assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); + assertOrPanic(os_info.Enum.fields[3].value == 3); + assertOrPanic(os_info.Enum.tag_type == u2); + assertOrPanic(os_info.Enum.defs.len == 0); +} + +test "type info: union info" { + testUnion(); + comptime testUnion(); +} + +fn testUnion() void { + const typeinfo_info = @typeInfo(TypeInfo); + assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); + assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); + assertOrPanic(typeinfo_info.Union.fields.len == 24); + assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); + assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); + assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); + assertOrPanic(typeinfo_info.Union.defs.len == 20); + + const TestNoTagUnion = union { + Foo: void, + Bar: u32, + }; + + const notag_union_info = @typeInfo(TestNoTagUnion); + assertOrPanic(TypeId(notag_union_info) == TypeId.Union); + assertOrPanic(notag_union_info.Union.tag_type == null); + assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(notag_union_info.Union.fields.len == 2); + assertOrPanic(notag_union_info.Union.fields[0].enum_field == null); + assertOrPanic(notag_union_info.Union.fields[1].field_type == u32); + + const TestExternUnion = extern union { + foo: *c_void, + }; + + const extern_union_info = @typeInfo(TestExternUnion); + assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + assertOrPanic(extern_union_info.Union.tag_type == null); + assertOrPanic(extern_union_info.Union.fields[0].enum_field == null); + assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void); +} + +test "type info: struct info" { + testStruct(); + comptime testStruct(); +} + +fn testStruct() void { + const struct_info = @typeInfo(TestStruct); + assertOrPanic(TypeId(struct_info) == TypeId.Struct); + assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + assertOrPanic(struct_info.Struct.fields.len == 3); + assertOrPanic(struct_info.Struct.fields[1].offset == null); + assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct); + assertOrPanic(struct_info.Struct.defs.len == 2); + assertOrPanic(struct_info.Struct.defs[0].is_pub); + assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); +} + +const TestStruct = packed struct { + const Self = @This(); + + fieldA: usize, + fieldB: void, + fieldC: *Self, + + pub fn foo(self: *const Self) void {} +}; + +test "type info: function type info" { + testFunction(); + comptime testFunction(); +} + +fn testFunction() void { + const fn_info = @typeInfo(@typeOf(foo)); + assertOrPanic(TypeId(fn_info) == TypeId.Fn); + assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); + assertOrPanic(fn_info.Fn.is_generic); + assertOrPanic(fn_info.Fn.args.len == 2); + assertOrPanic(fn_info.Fn.is_var_args); + assertOrPanic(fn_info.Fn.return_type == null); + assertOrPanic(fn_info.Fn.async_allocator_type == null); + + const test_instance: TestStruct = undefined; + const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); + assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn); + assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); +} + +fn foo(comptime a: usize, b: bool, args: ...) usize { + return 0; +} + +test "typeInfo with comptime parameter in struct fn def" { + const S = struct { + pub fn func(comptime x: f32) void {} + }; + comptime var info = @typeInfo(S); +} diff --git a/test/cases/undefined.zig b/test/stage1/behavior/undefined.zig similarity index 59% rename from test/cases/undefined.zig rename to test/stage1/behavior/undefined.zig index 83c620d211..333e217d49 100644 --- a/test/cases/undefined.zig +++ b/test/stage1/behavior/undefined.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const mem = @import("std").mem; fn initStaticArray() [10]i32 { @@ -11,16 +11,16 @@ fn initStaticArray() [10]i32 { } const static_array = initStaticArray(); test "init static array to undefined" { - assert(static_array[0] == 1); - assert(static_array[4] == 2); - assert(static_array[7] == 3); - assert(static_array[9] == 4); + assertOrPanic(static_array[0] == 1); + assertOrPanic(static_array[4] == 2); + assertOrPanic(static_array[7] == 3); + assertOrPanic(static_array[9] == 4); comptime { - assert(static_array[0] == 1); - assert(static_array[4] == 2); - assert(static_array[7] == 3); - assert(static_array[9] == 4); + assertOrPanic(static_array[0] == 1); + assertOrPanic(static_array[4] == 2); + assertOrPanic(static_array[7] == 3); + assertOrPanic(static_array[9] == 4); } } @@ -40,12 +40,12 @@ test "assign undefined to struct" { comptime { var foo: Foo = undefined; setFooX(&foo); - assert(foo.x == 2); + assertOrPanic(foo.x == 2); } { var foo: Foo = undefined; setFooX(&foo); - assert(foo.x == 2); + assertOrPanic(foo.x == 2); } } @@ -53,16 +53,17 @@ test "assign undefined to struct with method" { comptime { var foo: Foo = undefined; foo.setFooXMethod(); - assert(foo.x == 3); + assertOrPanic(foo.x == 3); } { var foo: Foo = undefined; foo.setFooXMethod(); - assert(foo.x == 3); + assertOrPanic(foo.x == 3); } } test "type name of undefined" { const x = undefined; - assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); + assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); } + diff --git a/test/cases/underscore.zig b/test/stage1/behavior/underscore.zig similarity index 91% rename from test/cases/underscore.zig rename to test/stage1/behavior/underscore.zig index da1c97659c..7443319336 100644 --- a/test/cases/underscore.zig +++ b/test/stage1/behavior/underscore.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; test "ignore lval with underscore" { _ = false; diff --git a/test/cases/union.zig b/test/stage1/behavior/union.zig similarity index 77% rename from test/cases/union.zig rename to test/stage1/behavior/union.zig index 019a7012da..c8e8feb11e 100644 --- a/test/cases/union.zig +++ b/test/stage1/behavior/union.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const Value = union(enum) { Int: u64, @@ -27,11 +27,11 @@ const array = []Value{ test "unions embedded in aggregate types" { switch (array[1]) { - Value.Array => |arr| assert(arr[4] == 3), + Value.Array => |arr| assertOrPanic(arr[4] == 3), else => unreachable, } switch ((err catch unreachable).val1) { - Value.Int => |x| assert(x == 1234), + Value.Int => |x| assertOrPanic(x == 1234), else => unreachable, } } @@ -43,18 +43,18 @@ const Foo = union { test "basic unions" { var foo = Foo{ .int = 1 }; - assert(foo.int == 1); + assertOrPanic(foo.int == 1); foo = Foo{ .float = 12.34 }; - assert(foo.float == 12.34); + assertOrPanic(foo.float == 12.34); } test "comptime union field access" { comptime { var foo = Foo{ .int = 0 }; - assert(foo.int == 0); + assertOrPanic(foo.int == 0); foo = Foo{ .float = 42.42 }; - assert(foo.float == 42.42); + assertOrPanic(foo.float == 42.42); } } @@ -62,10 +62,10 @@ test "init union with runtime value" { var foo: Foo = undefined; setFloat(&foo, 12.34); - assert(foo.float == 12.34); + assertOrPanic(foo.float == 12.34); setInt(&foo, 42); - assert(foo.int == 42); + assertOrPanic(foo.int == 42); } fn setFloat(foo: *Foo, x: f64) void { @@ -83,9 +83,9 @@ const FooExtern = extern union { test "basic extern unions" { var foo = FooExtern{ .int = 1 }; - assert(foo.int == 1); + assertOrPanic(foo.int == 1); foo.float = 12.34; - assert(foo.float == 12.34); + assertOrPanic(foo.float == 12.34); } const Letter = enum { @@ -105,11 +105,11 @@ test "union with specified enum tag" { } fn doTest() void { - assert(bar(Payload{ .A = 1234 }) == -10); + assertOrPanic(bar(Payload{ .A = 1234 }) == -10); } fn bar(value: Payload) i32 { - assert(Letter(value) == Letter.A); + assertOrPanic(Letter(value) == Letter.A); return switch (value) { Payload.A => |x| return x - 1244, Payload.B => |x| if (x == 12.34) i32(20) else 21, @@ -125,8 +125,8 @@ const MultipleChoice = union(enum(u32)) { }; test "simple union(enum(u32))" { var x = MultipleChoice.C; - assert(x == MultipleChoice.C); - assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60); + assertOrPanic(x == MultipleChoice.C); + assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60); } const MultipleChoice2 = union(enum(u32)) { @@ -142,14 +142,14 @@ const MultipleChoice2 = union(enum(u32)) { }; test "union(enum(u32)) with specified and unspecified tag values" { - comptime assert(@TagType(@TagType(MultipleChoice2)) == u32); + comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32); testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); - assert(1123 == switch (x) { + assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); + assertOrPanic(1123 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => |v| i32(1000) + v, @@ -167,7 +167,7 @@ const ExternPtrOrInt = extern union { int: u64, }; test "extern union size" { - comptime assert(@sizeOf(ExternPtrOrInt) == 8); + comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8); } const PackedPtrOrInt = packed union { @@ -175,14 +175,14 @@ const PackedPtrOrInt = packed union { int: u64, }; test "extern union size" { - comptime assert(@sizeOf(PackedPtrOrInt) == 8); + comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8); } const ZeroBits = union { OnlyField: void, }; test "union with only 1 field which is void should be zero bits" { - comptime assert(@sizeOf(ZeroBits) == 0); + comptime assertOrPanic(@sizeOf(ZeroBits) == 0); } const TheTag = enum { @@ -196,9 +196,9 @@ const TheUnion = union(TheTag) { C: i32, }; test "union field access gives the enum values" { - assert(TheUnion.A == TheTag.A); - assert(TheUnion.B == TheTag.B); - assert(TheUnion.C == TheTag.C); + assertOrPanic(TheUnion.A == TheTag.A); + assertOrPanic(TheUnion.B == TheTag.B); + assertOrPanic(TheUnion.C == TheTag.C); } test "cast union to tag type of union" { @@ -207,12 +207,12 @@ test "cast union to tag type of union" { } fn testCastUnionToTagType(x: TheUnion) void { - assert(TheTag(x) == TheTag.B); + assertOrPanic(TheTag(x) == TheTag.B); } test "cast tag type of union to union" { var x: Value2 = Letter2.B; - assert(Letter2(x) == Letter2.B); + assertOrPanic(Letter2(x) == Letter2.B); } const Letter2 = enum { A, @@ -227,11 +227,11 @@ const Value2 = union(Letter2) { test "implicit cast union to its tag type" { var x: Value2 = Letter2.B; - assert(x == Letter2.B); + assertOrPanic(x == Letter2.B); giveMeLetterB(x); } fn giveMeLetterB(x: Letter2) void { - assert(x == Value2.B); + assertOrPanic(x == Value2.B); } pub const PackThis = union(enum) { @@ -244,7 +244,7 @@ test "constant packed union" { } fn testConstPackedUnion(expected_tokens: []const PackThis) void { - assert(expected_tokens[0].StringLiteral == 1); + assertOrPanic(expected_tokens[0].StringLiteral == 1); } test "switch on union with only 1 field" { @@ -256,7 +256,7 @@ test "switch on union with only 1 field" { z = PartialInstWithPayload{ .Compiled = 1234 }; switch (z) { PartialInstWithPayload.Compiled => |x| { - assert(x == 1234); + assertOrPanic(x == 1234); return; }, } @@ -282,11 +282,11 @@ test "access a member of tagged union with conflicting enum tag name" { const B = void; }; - comptime assert(Bar.A == u8); + comptime assertOrPanic(Bar.A == u8); } test "tagged union initialization with runtime void" { - assert(testTaggedUnionInit({})); + assertOrPanic(testTaggedUnionInit({})); } const TaggedUnionWithAVoid = union(enum) { @@ -324,9 +324,9 @@ test "union with only 1 field casted to its enum type" { var e = Expr{ .Literal = Literal{ .Bool = true } }; const Tag = @TagType(Expr); - comptime assert(@TagType(Tag) == comptime_int); + comptime assertOrPanic(@TagType(Tag) == comptime_int); var t = Tag(e); - assert(t == Expr.Literal); + assertOrPanic(t == Expr.Literal); } test "union with only 1 field casted to its enum type which has enum value specified" { @@ -344,9 +344,9 @@ test "union with only 1 field casted to its enum type which has enum value speci }; var e = Expr{ .Literal = Literal{ .Bool = true } }; - comptime assert(@TagType(Tag) == comptime_int); + comptime assertOrPanic(@TagType(Tag) == comptime_int); var t = Tag(e); - assert(t == Expr.Literal); - assert(@enumToInt(t) == 33); - comptime assert(@enumToInt(t) == 33); + assertOrPanic(t == Expr.Literal); + assertOrPanic(@enumToInt(t) == 33); + comptime assertOrPanic(@enumToInt(t) == 33); } diff --git a/test/cases/var_args.zig b/test/stage1/behavior/var_args.zig similarity index 56% rename from test/cases/var_args.zig rename to test/stage1/behavior/var_args.zig index 3eb6e30448..1f782a3bb3 100644 --- a/test/cases/var_args.zig +++ b/test/stage1/behavior/var_args.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; fn add(args: ...) i32 { var sum = i32(0); @@ -12,9 +12,9 @@ fn add(args: ...) i32 { } test "add arbitrary args" { - assert(add(i32(1), i32(2), i32(3), i32(4)) == 10); - assert(add(i32(1234)) == 1234); - assert(add() == 0); + assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10); + assertOrPanic(add(i32(1234)) == 1234); + assertOrPanic(add() == 0); } fn readFirstVarArg(args: ...) void { @@ -26,9 +26,9 @@ test "send void arg to var args" { } test "pass args directly" { - assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); - assert(addSomeStuff(i32(1234)) == 1234); - assert(addSomeStuff() == 0); + assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); + assertOrPanic(addSomeStuff(i32(1234)) == 1234); + assertOrPanic(addSomeStuff() == 0); } fn addSomeStuff(args: ...) i32 { @@ -36,24 +36,24 @@ fn addSomeStuff(args: ...) i32 { } test "runtime parameter before var args" { - assert(extraFn(10) == 0); - assert(extraFn(10, false) == 1); - assert(extraFn(10, false, true) == 2); + assertOrPanic(extraFn(10) == 0); + assertOrPanic(extraFn(10, false) == 1); + assertOrPanic(extraFn(10, false, true) == 2); // TODO issue #313 //comptime { - // assert(extraFn(10) == 0); - // assert(extraFn(10, false) == 1); - // assert(extraFn(10, false, true) == 2); + // assertOrPanic(extraFn(10) == 0); + // assertOrPanic(extraFn(10, false) == 1); + // assertOrPanic(extraFn(10, false, true) == 2); //} } fn extraFn(extra: u32, args: ...) usize { if (args.len >= 1) { - assert(args[0] == false); + assertOrPanic(args[0] == false); } if (args.len >= 2) { - assert(args[1] == true); + assertOrPanic(args[1] == true); } return args.len; } @@ -71,8 +71,8 @@ fn foo2(args: ...) bool { } test "array of var args functions" { - assert(foos[0]()); - assert(!foos[1]()); + assertOrPanic(foos[0]()); + assertOrPanic(!foos[1]()); } test "pass zero length array to var args param" { diff --git a/test/cases/void.zig b/test/stage1/behavior/void.zig similarity index 67% rename from test/cases/void.zig rename to test/stage1/behavior/void.zig index 7121ac664b..431d3f4eb1 100644 --- a/test/cases/void.zig +++ b/test/stage1/behavior/void.zig @@ -1,4 +1,4 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; const Foo = struct { a: void, @@ -13,14 +13,14 @@ test "compare void with void compile time known" { .b = 1, .c = {}, }; - assert(foo.a == {}); + assertOrPanic(foo.a == {}); } } test "iterate over a void slice" { var j: usize = 0; for (times(10)) |_, i| { - assert(i == j); + assertOrPanic(i == j); j += 1; } } @@ -28,3 +28,8 @@ test "iterate over a void slice" { fn times(n: usize) []const void { return ([*]void)(undefined)[0..n]; } + +test "void optional" { + var x: ?void = {}; + assertOrPanic(x != null); +} diff --git a/test/cases/while.zig b/test/stage1/behavior/while.zig similarity index 83% rename from test/cases/while.zig rename to test/stage1/behavior/while.zig index f774e0ec6b..579b4e4db8 100644 --- a/test/cases/while.zig +++ b/test/stage1/behavior/while.zig @@ -1,12 +1,12 @@ -const assert = @import("std").debug.assert; +const assertOrPanic = @import("std").debug.assertOrPanic; test "while loop" { var i: i32 = 0; while (i < 4) { i += 1; } - assert(i == 4); - assert(whileLoop1() == 1); + assertOrPanic(i == 4); + assertOrPanic(whileLoop1() == 1); } fn whileLoop1() i32 { return whileLoop2(); @@ -16,8 +16,9 @@ fn whileLoop2() i32 { return 1; } } + test "static eval while" { - assert(static_eval_while_number == 1); + assertOrPanic(static_eval_while_number == 1); } const static_eval_while_number = staticWhileLoop1(); fn staticWhileLoop1() i32 { @@ -31,7 +32,7 @@ fn staticWhileLoop2() i32 { test "continue and break" { runContinueAndBreakTest(); - assert(continue_and_break_counter == 8); + assertOrPanic(continue_and_break_counter == 8); } var continue_and_break_counter: i32 = 0; fn runContinueAndBreakTest() void { @@ -44,7 +45,7 @@ fn runContinueAndBreakTest() void { } break; } - assert(i == 4); + assertOrPanic(i == 4); } test "return with implicit cast from while loop" { @@ -65,7 +66,7 @@ test "while with continue expression" { sum += i; } } - assert(sum == 40); + assertOrPanic(sum == 40); } test "while with else" { @@ -77,8 +78,8 @@ test "while with else" { } else { got_else += 1; } - assert(sum == 10); - assert(got_else == 1); + assertOrPanic(sum == 10); + assertOrPanic(got_else == 1); } test "while with optional as condition" { @@ -87,7 +88,7 @@ test "while with optional as condition" { while (getNumberOrNull()) |value| { sum += value; } - assert(sum == 45); + assertOrPanic(sum == 45); } test "while with optional as condition with else" { @@ -96,12 +97,12 @@ test "while with optional as condition with else" { var got_else: i32 = 0; while (getNumberOrNull()) |value| { sum += value; - assert(got_else == 0); + assertOrPanic(got_else == 0); } else { got_else += 1; } - assert(sum == 45); - assert(got_else == 1); + assertOrPanic(sum == 45); + assertOrPanic(got_else == 1); } test "while with error union condition" { @@ -111,11 +112,11 @@ test "while with error union condition" { while (getNumberOrErr()) |value| { sum += value; } else |err| { - assert(err == error.OutOfNumbers); + assertOrPanic(err == error.OutOfNumbers); got_else += 1; } - assert(sum == 45); - assert(got_else == 1); + assertOrPanic(sum == 45); + assertOrPanic(got_else == 1); } var numbers_left: i32 = undefined; @@ -137,7 +138,7 @@ test "while on optional with else result follow else prong" { break value; } else i32(2); - assert(result == 2); + assertOrPanic(result == 2); } test "while on optional with else result follow break prong" { @@ -145,7 +146,7 @@ test "while on optional with else result follow break prong" { break value; } else i32(2); - assert(result == 10); + assertOrPanic(result == 10); } test "while on error union with else result follow else prong" { @@ -153,7 +154,7 @@ test "while on error union with else result follow else prong" { break value; } else |err| i32(2); - assert(result == 2); + assertOrPanic(result == 2); } test "while on error union with else result follow break prong" { @@ -161,7 +162,7 @@ test "while on error union with else result follow break prong" { break value; } else |err| i32(2); - assert(result == 10); + assertOrPanic(result == 10); } test "while on bool with else result follow else prong" { @@ -169,7 +170,7 @@ test "while on bool with else result follow else prong" { break i32(10); } else i32(2); - assert(result == 2); + assertOrPanic(result == 2); } test "while on bool with else result follow break prong" { @@ -177,7 +178,7 @@ test "while on bool with else result follow break prong" { break i32(10); } else i32(2); - assert(result == 10); + assertOrPanic(result == 10); } test "break from outer while loop" { diff --git a/test/cases/widening.zig b/test/stage1/behavior/widening.zig similarity index 75% rename from test/cases/widening.zig rename to test/stage1/behavior/widening.zig index cf6ab4ca0f..7577868aff 100644 --- a/test/cases/widening.zig +++ b/test/stage1/behavior/widening.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assert = std.debug.assert; +const assertOrPanic = std.debug.assertOrPanic; const mem = std.mem; test "integer widening" { @@ -9,13 +9,13 @@ test "integer widening" { var d: u64 = c; var e: u64 = d; var f: u128 = e; - assert(f == a); + assertOrPanic(f == a); } test "implicit unsigned integer to signed integer" { var a: u8 = 250; var b: i16 = a; - assert(b == 250); + assertOrPanic(b == 250); } test "float widening" { @@ -23,5 +23,6 @@ test "float widening" { var b: f32 = a; var c: f64 = b; var d: f128 = c; - assert(d == a); + assertOrPanic(d == a); } + From 9ca94bbba55b523abe3544e87c1710a83064d29a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 02:53:50 -0500 Subject: [PATCH 120/218] fix freebsd ci from previous commit --- .builds/freebsd.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index c7d92712b0..934b8a4f4a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -12,28 +12,28 @@ tasks: ninja install - test: | cd zig/build - bin/zig test ../test/behavior.zig + bin/zig test ../test/stage1/behavior.zig bin/zig test ../std/special/compiler_rt/index.zig - bin/zig test ../test/behavior.zig --library c + bin/zig test ../test/stage1/behavior.zig --library c bin/zig test ../std/special/compiler_rt/index.zig --library c - bin/zig test ../test/behavior.zig --release-fast + bin/zig test ../test/stage1/behavior.zig --release-fast bin/zig test ../std/special/compiler_rt/index.zig --release-fast - bin/zig test ../test/behavior.zig --release-fast --library c + 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 ../test/behavior.zig --release-small --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 ../test/behavior.zig --release-small + bin/zig test ../test/stage1/behavior.zig --release-small bin/zig test ../std/special/compiler_rt/index.zig --release-small - bin/zig test ../test/behavior.zig --release-safe + bin/zig test ../test/stage1/behavior.zig --release-safe bin/zig test ../std/special/compiler_rt/index.zig --release-safe - bin/zig test ../test/behavior.zig --release-safe --library c + bin/zig test ../test/stage1/behavior.zig --release-safe --library c bin/zig test ../std/special/compiler_rt/index.zig --release-safe --library c # TODO enable all tests #bin/zig build --build-file ../build.zig test From ecb0cb661a75a130cf6978fa42d464e2d654d8df Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 02:53:59 -0500 Subject: [PATCH 121/218] darwin time code: don't cast to int until the end See #1648 --- std/os/time.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/os/time.zig b/std/os/time.zig index 42f32f8fee..304f65206a 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -84,9 +84,9 @@ fn milliTimestampDarwin() u64 { var tv: darwin.timeval = undefined; var err = darwin.gettimeofday(&tv, null); debug.assert(err == 0); - const sec_ms = @intCast(u64, tv.tv_sec) * ms_per_s; - const usec_ms = @divFloor(@intCast(u64, tv.tv_usec), us_per_s / ms_per_s); - return u64(sec_ms) + u64(usec_ms); + const sec_ms = tv.tv_sec * ms_per_s; + const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s); + return @intCast(u64, sec_ms + usec_ms); } fn milliTimestampPosix() u64 { From ad8381e0d2936ffecaa0b54e51e26d6bdb98682e Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Tue, 29 Jan 2019 16:20:38 -0800 Subject: [PATCH 122/218] Move tokenizer error location to offending char Previously, it pointed to the start of the current token, but this made it difficult to tell where the error occurred when it was, say, in the middle of a string. --- src/tokenizer.cpp | 9 ++------- test/compile_errors.zig | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 6215541876..d43bfabf6d 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -248,13 +248,8 @@ ATTRIBUTE_PRINTF(2, 3) static void tokenize_error(Tokenize *t, const char *format, ...) { t->state = TokenizeStateError; - if (t->cur_tok) { - t->out->err_line = t->cur_tok->start_line; - t->out->err_column = t->cur_tok->start_column; - } else { - t->out->err_line = t->line; - t->out->err_column = t->column; - } + t->out->err_line = t->line; + t->out->err_column = t->column; va_list ap; va_start(ap, format); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index bc1ef660c3..2aca7e9141 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2645,7 +2645,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:1:13: error: newline not allowed in string literal", + ".tmp_source.zig:1:15: error: newline not allowed in string literal", ); cases.add( From 59c050e7ff83aeecd507cef24d7eb914ec59581d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 16:06:18 -0500 Subject: [PATCH 123/218] collapse os_file_mtime into os_file_open_r and check for directory This is a manual merge of kristate's pull request #1754, due to conflicts + a couple fixups. closes #1754 --- src/cache_hash.cpp | 16 +++--------- src/os.cpp | 62 +++++++++++++++++++++++----------------------- src/os.hpp | 3 +-- 3 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index 5e6c3b9a9d..4526a83c27 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -222,14 +222,9 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents assert(chf->path != nullptr); OsFile this_file; - if ((err = os_file_open_r(chf->path, &this_file))) + if ((err = os_file_open_r(chf->path, &this_file, &chf->mtime))) return err; - if ((err = os_file_mtime(this_file, &chf->mtime))) { - os_file_close(this_file); - return err; - } - if ((err = hash_file(chf->bin_digest, this_file, contents))) { os_file_close(this_file); return err; @@ -351,17 +346,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { // if the mtime matches we can trust the digest OsFile this_file; - if ((err = os_file_open_r(chf->path, &this_file))) { + OsTimeStamp actual_mtime; + if ((err = os_file_open_r(chf->path, &this_file, &actual_mtime))) { fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); os_file_close(ch->manifest_file); return ErrorCacheUnavailable; } - OsTimeStamp actual_mtime; - if ((err = os_file_mtime(this_file, &actual_mtime))) { - os_file_close(this_file); - os_file_close(ch->manifest_file); - return err; - } if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) { os_file_close(this_file); } else { diff --git a/src/os.cpp b/src/os.cpp index 2f0379c09b..7157867358 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1808,7 +1808,7 @@ Error os_self_exe_shared_libs(ZigList &paths) { #endif } -Error os_file_open_r(Buf *full_path, OsFile *out_file) { +Error os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime) { #if defined(ZIG_OS_WINDOWS) // TODO use CreateFileW HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); @@ -1834,8 +1834,18 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { return ErrorUnexpected; } } - *out_file = result; + + if (mtime != nullptr) { + FILETIME last_write_time; + if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) { + CloseHandle(result); + return ErrorUnexpected; + } + mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; + mtime->nsec = 0; + } + return ErrorNone; #else for (;;) { @@ -1858,7 +1868,26 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { return ErrorFileSystem; } } + struct stat statbuf; + if (fstat(fd, &statbuf) == -1) { + close(fd); + return ErrorFileSystem; + } + if (S_ISDIR(statbuf.st_mode)) { + close(fd); + return ErrorIsDir; + } *out_file = fd; + + if (mtime != nullptr) { +#if defined(ZIG_OS_DARWIN) + mtime->sec = statbuf.st_mtimespec.tv_sec; + mtime->nsec = statbuf.st_mtimespec.tv_nsec; +#else + mtime->sec = statbuf.st_mtim.tv_sec; + mtime->nsec = statbuf.st_mtim.tv_nsec; +#endif + } return ErrorNone; } #endif @@ -1948,35 +1977,6 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { #endif } -Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { -#if defined(ZIG_OS_WINDOWS) - FILETIME last_write_time; - if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) - return ErrorUnexpected; - mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; - mtime->nsec = 0; - return ErrorNone; -#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) - struct stat statbuf; - if (fstat(file, &statbuf) == -1) - return ErrorFileSystem; - - mtime->sec = statbuf.st_mtim.tv_sec; - mtime->nsec = statbuf.st_mtim.tv_nsec; - return ErrorNone; -#elif defined(ZIG_OS_DARWIN) - struct stat statbuf; - if (fstat(file, &statbuf) == -1) - return ErrorFileSystem; - - mtime->sec = statbuf.st_mtimespec.tv_sec; - mtime->nsec = statbuf.st_mtimespec.tv_nsec; - return ErrorNone; -#else -#error unimplemented -#endif -} - Error os_file_read(OsFile file, void *ptr, size_t *len) { #if defined(ZIG_OS_WINDOWS) DWORD amt_read; diff --git a/src/os.hpp b/src/os.hpp index d81a2362a5..68ac6e0171 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -101,9 +101,8 @@ bool os_path_is_absolute(Buf *path); Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); -Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file); +Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime); Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); -Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime); Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents); From 169a789b343e9070b4658de9c8bd96c6736c6edc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 16:12:30 -0500 Subject: [PATCH 124/218] fix test after merging ad8381e0d2936f this test slipped through due to branching --- test/compile_errors.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2aca7e9141..f2a2ba2641 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -10,7 +10,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return 5678; \\} , - ".tmp_source.zig:2:11: error: `&&` is invalid. Note that `and` is boolean AND.", + ".tmp_source.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.", ); cases.add( From 545064c1d9137a603e3e28aa066ce9e65a1ed4b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 23:36:52 -0500 Subject: [PATCH 125/218] introduce vector type for SIMD See #903 * create with `@Vector(len, ElemType)` * only wrapping addition is implemented This feature is far from complete; this is only the beginning. --- doc/langref.html.in | 34 +++++ src-self-hosted/type.zig | 16 +++ src/all_types.hpp | 26 ++++ src/analyze.cpp | 91 +++++++++++- src/analyze.hpp | 1 + src/codegen.cpp | 47 ++++++- src/ir.cpp | 213 +++++++++++++++++++++++------ src/ir_print.cpp | 11 ++ src/zig_llvm.cpp | 13 ++ src/zig_llvm.h | 3 + std/hash_map.zig | 2 + test/stage1/behavior/type_info.zig | 16 ++- 12 files changed, 419 insertions(+), 54 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 909c0f5817..e192dbbf76 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1531,6 +1531,29 @@ test "array initialization with function calls" { {#code_end#} {#see_also|for|Slices#} {#header_close#} + + {#header_open|Vectors#} +

+ A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on + in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin + function {#link|@Vector#}. +

+

+ TODO talk about C ABI interop +

+ {#header_open|SIMD#} +

+ TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the + docs with: + * What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector? + * How to convert to/from vectors/arrays + * How to access individual elements from vectors, how to loop over the elements + * "shuffle" + * Advice on writing high perf software, how to abstract the best way +

+ {#header_close#} + {#header_close#} + {#header_open|Pointers#}

Zig has two kinds of pointers: @@ -6607,6 +6630,17 @@ pub const TypeInfo = union(TypeId) { expression passed as an argument. The expression is evaluated.

+ {#header_close#} + + {#header_open|@Vector#} +
{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}
+

+ This function returns a vector type for {#link|SIMD#}. +

+

+ {#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a + {#link|pointer|Pointers#}. +

{#header_close#} {#header_close#} diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index aa00bb876d..fa31343902 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -44,6 +44,7 @@ pub const Type = struct { Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp), Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp), Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp), + Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp), } } @@ -77,6 +78,7 @@ pub const Type = struct { Id.ArgTuple => unreachable, Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context), Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context), + Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context), } } @@ -103,6 +105,7 @@ pub const Type = struct { Id.Enum, Id.Fn, Id.Promise, + Id.Vector, => return false, Id.Struct => @panic("TODO"), @@ -135,6 +138,7 @@ pub const Type = struct { Id.Float, Id.Fn, Id.Promise, + Id.Vector, => return true, Id.Pointer => { @@ -902,6 +906,18 @@ pub const Type = struct { } }; + pub const Vector = struct { + base: Type, + + pub fn destroy(self: *Vector, comp: *Compilation) void { + comp.gpa().destroy(self); + } + + pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + @panic("TODO"); + } + }; + pub const ComptimeFloat = struct { base: Type, diff --git a/src/all_types.hpp b/src/all_types.hpp index 4b134361a3..f6fe72891d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -252,6 +252,10 @@ struct ConstArgTuple { size_t end_index; }; +struct ConstVector { + ConstExprValue *elements; +}; + enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, @@ -318,6 +322,7 @@ struct ConstExprValue { ConstPtrValue x_ptr; ImportTableEntry *x_import; ConstArgTuple x_arg_tuple; + ConstVector x_vector; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -1210,6 +1215,12 @@ struct ZigTypePromise { ZigType *result_type; }; +struct ZigTypeVector { + // The type must be a pointer, integer, or float + ZigType *elem_type; + uint32_t len; +}; + enum ZigTypeId { ZigTypeIdInvalid, ZigTypeIdMetaType, @@ -1236,6 +1247,7 @@ enum ZigTypeId { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdPromise, + ZigTypeIdVector, }; struct ZigType { @@ -1262,6 +1274,7 @@ struct ZigType { ZigTypeFn fn; ZigTypeBoundFn bound_fn; ZigTypePromise promise; + ZigTypeVector vector; } data; // use these fields to make sure we don't duplicate type table entries for the same type @@ -1415,6 +1428,7 @@ enum BuiltinFnId { BuiltinFnIdEnumToInt, BuiltinFnIdIntToEnum, BuiltinFnIdIntType, + BuiltinFnIdVectorType, BuiltinFnIdSetCold, BuiltinFnIdSetRuntimeSafety, BuiltinFnIdSetFloatMode, @@ -1505,6 +1519,10 @@ struct TypeId { ZigType *err_set_type; ZigType *payload_type; } error_union; + struct { + ZigType *elem_type; + uint32_t len; + } vector; } data; }; @@ -2139,6 +2157,7 @@ enum IrInstructionId { IrInstructionIdFloatToInt, IrInstructionIdBoolToInt, IrInstructionIdIntType, + IrInstructionIdVectorType, IrInstructionIdBoolNot, IrInstructionIdMemset, IrInstructionIdMemcpy, @@ -2807,6 +2826,13 @@ struct IrInstructionIntType { IrInstruction *bit_count; }; +struct IrInstructionVectorType { + IrInstruction base; + + IrInstruction *len; + IrInstruction *elem_type; +}; + struct IrInstructionBoolNot { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 194888068c..99378eb7a8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return nullptr; } zig_unreachable(); @@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return true; } zig_unreachable(); @@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { } if (g->zig_target.arch.arch == ZigLLVM_x86_64) { X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); - if (abi_class == X64CABIClass_MEMORY) { - return true; - } - zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", - buf_ptr(&fn_type_id->return_type->name)); + return abi_class == X64CABIClass_MEMORY; } else if (target_is_arm(&g->zig_target)) { return type_size(g, fn_type_id->return_type) > 16; } @@ -1424,6 +1422,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdFn: + case ZigTypeIdVector: return true; case ZigTypeIdStruct: return type_entry->data.structure.layout == ContainerLayoutPacked; @@ -1472,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { default: return false; } + case ZigTypeIdVector: + return type_allowed_in_extern(g, type_entry->data.vector.elem_type); case ZigTypeIdFloat: return true; case ZigTypeIdArray: @@ -1625,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, type_entry)) { case ReqCompTimeNo: break; @@ -1720,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, fn_type_id.return_type)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; @@ -3577,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry case ZigTypeIdFn: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: return type_entry; } zig_unreachable(); @@ -3943,6 +3947,7 @@ static bool is_container(ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; } zig_unreachable(); @@ -4002,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: zig_unreachable(); } } @@ -4451,6 +4457,34 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return new_entry; } +ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { + TypeId type_id = {}; + type_id.id = ZigTypeIdVector; + type_id.data.vector.len = len; + type_id.data.vector.elem_type = elem_type; + + { + auto entry = g->type_table.maybe_get(type_id); + if (entry) + return entry->value; + } + + ZigType *entry = new_type_table_entry(ZigTypeIdVector); + entry->zero_bits = (len == 0) || !type_has_bits(elem_type); + entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len); + entry->data.vector.len = len; + entry->data.vector.elem_type = elem_type; + + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); + + entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len, + LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type); + + g->type_table.put(type_id, entry); + return entry; +} + ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { return &g->builtin_types.entry_c_int[c_int_type]; } @@ -4482,6 +4516,7 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdFn: case ZigTypeIdEnum: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; case ZigTypeIdArray: case ZigTypeIdStruct: @@ -4914,6 +4949,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { 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; case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -4966,6 +5004,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdBool: case ZigTypeIdUnreachable: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -5049,6 +5088,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdPointer: + case ZigTypeIdVector: return true; case ZigTypeIdArray: @@ -5201,6 +5241,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdInt: + case ZigTypeIdVector: return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; case ZigTypeIdPointer: return type_has_one_possible_value(g, type_entry->data.pointer.child_type); @@ -5251,6 +5292,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdBool: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdVoid: case ZigTypeIdUnreachable: @@ -5777,7 +5819,7 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; i += 1) { if (!const_values_equal(g, &a_elems[i], &b_elems[i])) return false; } @@ -5811,6 +5853,20 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { 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; + case ZigTypeIdVector: { + assert(a->type->data.vector.len == b->type->data.vector.len); + + size_t len = a->type->data.vector.len; + ConstExprValue *a_elems = a->data.x_vector.elements; + ConstExprValue *b_elems = b->data.x_vector.elements; + + for (size_t i = 0; i < len; i += 1) { + if (!const_values_equal(g, &a_elems[i], &b_elems[i])) + return false; + } + + return true; + } case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -6042,6 +6098,18 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } } zig_unreachable(); + case ZigTypeIdVector: { + buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); + uint64_t len = type_entry->data.vector.len; + for (uint32_t i = 0; i < len; i += 1) { + if (i != 0) + buf_appendf(buf, ","); + ConstExprValue *child_value = &const_val->data.x_vector.elements[i]; + render_const_value(g, buf, child_value); + } + buf_appendf(buf, "}"); + return; + } case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -6200,6 +6268,8 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdInt: return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); + case ZigTypeIdVector: + return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681); } zig_unreachable(); } @@ -6248,6 +6318,9 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdInt: return a.data.integer.is_signed == b.data.integer.is_signed && a.data.integer.bit_count == b.data.integer.bit_count; + case ZigTypeIdVector: + return a.data.vector.elem_type == b.data.vector.elem_type && + a.data.vector.len == b.data.vector.len; } zig_unreachable(); } @@ -6382,6 +6455,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdPromise, + ZigTypeIdVector, }; ZigTypeId type_id_at_index(size_t index) { @@ -6447,6 +6521,8 @@ size_t type_id_index(ZigType *entry) { return 22; case ZigTypeIdPromise: return 23; + case ZigTypeIdVector: + return 24; } zig_unreachable(); } @@ -6503,6 +6579,8 @@ const char *type_id_name(ZigTypeId id) { return "Opaque"; case ZigTypeIdPromise: return "Promise"; + case ZigTypeIdVector: + return "Vector"; } zig_unreachable(); } @@ -6658,6 +6736,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { case ZigTypeIdBool: return X64CABIClass_INTEGER; case ZigTypeIdFloat: + case ZigTypeIdVector: return X64CABIClass_SSE; case ZigTypeIdStruct: { // "If the size of an object is larger than four eightbytes, or it contains unaligned diff --git a/src/analyze.hpp b/src/analyze.hpp index 1bac15ebcc..da5265a594 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint64_t type_size(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); +ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); diff --git a/src/codegen.cpp b/src/codegen.cpp index 2f360735dd..e2576f5335 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1980,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ break; } - if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || + if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector || ty->id == ZigTypeIdInt // TODO investigate if we need to change this ) { switch (fn_walk->id) { @@ -2660,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, } else { return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); } + } else if (type_entry->id == ZigTypeIdVector) { + ZigType *elem_type = type_entry->data.vector.elem_type; + if (elem_type->id == ZigTypeIdFloat) { + ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); + return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); + } else if (elem_type->id == ZigTypeIdPointer) { + zig_panic("TODO codegen for pointers in vectors"); + } else if (elem_type->id == ZigTypeIdInt) { + bool is_wrapping = (op_id == IrBinOpAddWrap); + if (is_wrapping) { + return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); + } else if (want_runtime_safety) { + zig_panic("TODO runtime safety for vector integer addition"); + } else if (elem_type->data.integral.is_signed) { + return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); + } + } else { + zig_unreachable(); + } } else { zig_unreachable(); } @@ -5211,6 +5232,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCUndef: case IrInstructionIdEmbedFile: case IrInstructionIdIntType: + case IrInstructionIdVectorType: case IrInstructionIdMemberCount: case IrInstructionIdMemberType: case IrInstructionIdMemberName: @@ -5620,6 +5642,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con } case ZigTypeIdArray: zig_panic("TODO bit pack an array"); + case ZigTypeIdVector: + zig_panic("TODO bit pack a vector"); case ZigTypeIdUnion: zig_panic("TODO bit pack a union"); case ZigTypeIdStruct: @@ -5992,6 +6016,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c } } } + case ZigTypeIdVector: { + uint32_t len = type_entry->data.vector.len; + LLVMValueRef *values = allocate(len); + for (uint32_t i = 0; i < len; i += 1) { + values[i] = gen_const_val(g, &const_val->data.x_vector.elements[i], ""); + } + return LLVMConstVector(values, len); + } case ZigTypeIdUnion: { LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; @@ -6927,6 +6959,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int + create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); @@ -7152,6 +7185,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " ArgTuple: void,\n" " Opaque: void,\n" " Promise: Promise,\n" + " Vector: Vector,\n" "\n\n" " pub const Int = struct {\n" " is_signed: bool,\n" @@ -7270,6 +7304,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " child: ?type,\n" " };\n" "\n" + " pub const Vector = struct {\n" + " len: u32,\n" + " child: type,\n" + " };\n" + "\n" " pub const Definition = struct {\n" " name: []const u8,\n" " is_pub: bool,\n" @@ -7841,6 +7880,9 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e case ZigTypeIdArray: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); return; + case ZigTypeIdVector: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type); + return; case ZigTypeIdOptional: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); return; @@ -7972,6 +8014,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu buf_appendf(out_buf, "%s", buf_ptr(child_buf)); return; } + case ZigTypeIdVector: + zig_panic("TODO implement get_c_type for vector types"); case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdFn: @@ -8137,6 +8181,7 @@ static void gen_h_file(CodeGen *g) { case ZigTypeIdOptional: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: zig_unreachable(); case ZigTypeIdEnum: if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { diff --git a/src/ir.cpp b/src/ir.cpp index 06eb4a47f1..d5152f3c85 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -587,6 +587,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) { return IrInstructionIdIntType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { + return IrInstructionIdVectorType; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { return IrInstructionIdBoolNot; } @@ -1953,6 +1957,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *len, + IrInstruction *elem_type) +{ + IrInstructionVectorType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->len = len; + instruction->elem_type = elem_type; + + ir_ref_instruction(len, irb->current_basic_block); + ir_ref_instruction(elem_type, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { IrInstructionBoolNot *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; @@ -4230,6 +4247,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, int_type, lval); } + case BuiltinFnIdVectorType: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, vector_type, lval); + } case BuiltinFnIdMemcpy: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -11617,6 +11649,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdComptimeInt: case ZigTypeIdInt: case ZigTypeIdFloat: + case ZigTypeIdVector: operator_allowed = true; break; @@ -12032,6 +12065,48 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b return result; } +static bool ok_float_op(IrBinOp op) { + switch (op) { + case IrBinOpInvalid: + zig_unreachable(); + case IrBinOpAdd: + case IrBinOpSub: + case IrBinOpMult: + case IrBinOpDivUnspecified: + case IrBinOpDivTrunc: + case IrBinOpDivFloor: + case IrBinOpDivExact: + case IrBinOpRemRem: + case IrBinOpRemMod: + return true; + + case IrBinOpBoolOr: + case IrBinOpBoolAnd: + case IrBinOpCmpEq: + case IrBinOpCmpNotEq: + case IrBinOpCmpLessThan: + case IrBinOpCmpGreaterThan: + case IrBinOpCmpLessOrEq: + case IrBinOpCmpGreaterOrEq: + case IrBinOpBinOr: + case IrBinOpBinXor: + case IrBinOpBinAnd: + case IrBinOpBitShiftLeftLossy: + case IrBinOpBitShiftLeftExact: + case IrBinOpBitShiftRightLossy: + case IrBinOpBitShiftRightExact: + case IrBinOpAddWrap: + case IrBinOpSubWrap: + case IrBinOpMultWrap: + case IrBinOpRemUnspecified: + case IrBinOpArrayCat: + case IrBinOpArrayMult: + case IrBinOpMergeErrorSets: + return false; + } + zig_unreachable(); +} + static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) @@ -12169,21 +12244,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp op_id = IrBinOpRemRem; } + bool ok = false; if (is_int) { - // int - } else if (is_float && - (op_id == IrBinOpAdd || - op_id == IrBinOpSub || - op_id == IrBinOpMult || - op_id == IrBinOpDivUnspecified || - op_id == IrBinOpDivTrunc || - op_id == IrBinOpDivFloor || - op_id == IrBinOpDivExact || - op_id == IrBinOpRemRem || - op_id == IrBinOpRemMod)) - { - // float - } else { + ok = true; + } else if (is_float && ok_float_op(op_id)) { + ok = true; + } else if (resolved_type->id == ZigTypeIdVector) { + ZigType *elem_type = resolved_type->data.vector.elem_type; + if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) { + ok = true; + } else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) { + ok = true; + } + } + if (!ok) { AstNode *source_node = instruction->base.source_node; ir_add_error_node(ira, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'", @@ -12817,6 +12891,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdBool: + case ZigTypeIdVector: break; case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -12851,6 +12926,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: + case ZigTypeIdVector: zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); case ZigTypeIdNamespace: case ZigTypeIdBoundFn: @@ -14009,6 +14085,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ case ZigTypeIdVoid: case ZigTypeIdBool: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdPointer: case ZigTypeIdArray: @@ -15383,37 +15460,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio ZigType *type_entry = expr_value->value.type; if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); // handled above - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdNamespace: - case ZigTypeIdBoundFn: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdArgTuple: - case ZigTypeIdOpaque: - case ZigTypeIdPromise: - return ir_const_type(ira, &typeof_instruction->base, type_entry); - } - - zig_unreachable(); + return ir_const_type(ira, &typeof_instruction->base, type_entry); } static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, @@ -15652,6 +15699,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -15772,6 +15820,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { if ((err = ensure_complete_type(ira->codegen, child_type))) return ira->codegen->invalid_instruction; @@ -15838,6 +15887,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { uint64_t size_in_bytes = type_size(ira->codegen, type_entry); return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); @@ -16307,6 +16357,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: + case ZigTypeIdVector: ir_add_error(ira, &switch_target_instruction->base, buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; @@ -17496,6 +17547,27 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE break; } + case ZigTypeIdVector: { + result = create_const_vals(1); + result->special = ConstValSpecialStatic; + result->type = ir_type_info_get_type(ira, "Vector", nullptr); + + ConstExprValue *fields = create_const_vals(2); + result->data.x_struct.fields = fields; + + // len: usize + ensure_field_index(result->type, "len", 0); + fields[0].special = ConstValSpecialStatic; + fields[0].type = ira->codegen->builtin_types.entry_u32; + bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len); + // child: type + ensure_field_index(result->type, "child", 1); + fields[1].special = ConstValSpecialStatic; + fields[1].type = ira->codegen->builtin_types.entry_type; + fields[1].data.x_type = type_entry->data.vector.elem_type; + + break; + } case ZigTypeIdOptional: { result = create_const_vals(1); @@ -18671,6 +18743,30 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count)); } +static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstructionVectorType *instruction) { + uint64_t len; + if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) + return ira->codegen->invalid_instruction; + + ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); + if (type_is_invalid(elem_type)) + return ira->codegen->invalid_instruction; + + if (elem_type->id != ZigTypeIdInt && + elem_type->id != ZigTypeIdFloat && + get_codegen_ptr_type(elem_type) == nullptr) + { + ir_add_error(ira, instruction->elem_type, + buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", + buf_ptr(&elem_type->name))); + return ira->codegen->invalid_instruction; + } + + ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); + + return ir_const_type(ira, &instruction->base, vector_type); +} + static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) @@ -19474,6 +19570,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct case ZigTypeIdEnum: case ZigTypeIdUnion: case ZigTypeIdFn: + case ZigTypeIdVector: { uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); return ir_const_unsigned(ira, &instruction->base, align_in_bytes); @@ -20311,6 +20408,15 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue } } return; + case ZigTypeIdVector: { + size_t buf_i = 0; + for (uint32_t elem_i = 0; elem_i < val->type->data.vector.len; elem_i += 1) { + ConstExprValue *elem = &val->data.x_vector.elements[elem_i]; + buf_write_value_bytes(codegen, &buf[buf_i], elem); + buf_i += type_size(codegen, elem->type); + } + return; + } case ZigTypeIdStruct: zig_panic("TODO buf_write_value_bytes struct type"); case ZigTypeIdOptional: @@ -20387,6 +20493,20 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou } zig_unreachable(); } + case ZigTypeIdVector: { + uint64_t elem_size = type_size(codegen, val->type->data.vector.elem_type); + uint32_t len = val->type->data.vector.len; + + val->data.x_vector.elements = create_const_vals(len); + for (uint32_t i = 0; i < len; i += 1) { + ConstExprValue *elem = &val->data.x_vector.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = val->type->data.vector.elem_type; + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) + return err; + } + return ErrorNone; + } case ZigTypeIdEnum: switch (val->type->data.enumeration.layout) { case ContainerLayoutAuto: @@ -21633,6 +21753,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction); case IrInstructionIdIntType: return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); + case IrInstructionIdVectorType: + return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); case IrInstructionIdBoolNot: return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); case IrInstructionIdMemset: @@ -21943,6 +22065,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEmbedFile: case IrInstructionIdTruncate: case IrInstructionIdIntType: + case IrInstructionIdVectorType: case IrInstructionIdBoolNot: case IrInstructionIdSlice: case IrInstructionIdMemberCount: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a3ec8e9d35..a1fd450b65 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -719,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { fprintf(irp->f, ")"); } +static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) { + fprintf(irp->f, "@Vector("); + ir_print_other_instruction(irp, instruction->len); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->elem_type); + fprintf(irp->f, ")"); +} + static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { fprintf(irp->f, "! "); ir_print_other_instruction(irp, instruction->value); @@ -1577,6 +1585,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdIntType: ir_print_int_type(irp, (IrInstructionIntType *)instruction); break; + case IrInstructionIdVectorType: + ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); + break; case IrInstructionIdBoolNot: ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); break; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 3c01a0954d..65f6b5abb7 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch return reinterpret_cast(di_type); } +struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, + uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty) +{ + SmallVector subrange; + subrange.push_back(reinterpret_cast(dibuilder)->getOrCreateSubrange(0, Size)); + DIType *di_type = reinterpret_cast(dibuilder)->createVectorType( + Size, + AlignInBits, + reinterpret_cast(Ty), + reinterpret_cast(dibuilder)->getOrCreateArray(subrange)); + return reinterpret_cast(di_type); +} + ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits, uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 551a4a7448..26dca1198b 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -191,6 +191,9 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram); +ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, + uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty); + ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder); diff --git a/std/hash_map.zig b/std/hash_map.zig index 99237047e0..a63a549814 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), + builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"), builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), builtin.TypeId.Union => @compileError("TODO auto hash for unions"), builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), @@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), builtin.TypeId.Union => @compileError("TODO auto eql for unions"), builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"), + builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"), } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 5ad80e06e1..f3bb17b282 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -171,11 +171,11 @@ fn testUnion() void { assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); - assertOrPanic(typeinfo_info.Union.fields.len == 24); + assertOrPanic(typeinfo_info.Union.fields.len == 25); assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assertOrPanic(typeinfo_info.Union.defs.len == 20); + assertOrPanic(typeinfo_info.Union.defs.len == 21); const TestNoTagUnion = union { Foo: void, @@ -262,3 +262,15 @@ test "typeInfo with comptime parameter in struct fn def" { }; comptime var info = @typeInfo(S); } + +test "type info: vectors" { + testVector(); + comptime testVector(); +} + +fn testVector() void { + const vec_info = @typeInfo(@Vector(4, i32)); + assertOrPanic(TypeId(vec_info) == TypeId.Vector); + assertOrPanic(vec_info.Vector.len == 4); + assertOrPanic(vec_info.Vector.child == i32); +} From 28873e762295d0e03bf913d45d5317aae8d57bcd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 31 Jan 2019 16:52:59 -0500 Subject: [PATCH 126/218] os.cpp: fix regression on Windows from 59c050e7 --- src/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.cpp b/src/os.cpp index 7157867358..8eb6b34654 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1838,7 +1838,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsTimeStamp *mtime) { if (mtime != nullptr) { FILETIME last_write_time; - if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) { + if (!GetFileTime(result, nullptr, nullptr, &last_write_time)) { CloseHandle(result); return ErrorUnexpected; } From 7a4ed10981cf7ac5bed93b2c9bad280ad31c50cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 31 Jan 2019 18:47:45 -0500 Subject: [PATCH 127/218] darwin: fix incorrect timeval struct type closes #1648 I also added some more extern functions for darwin time functions, although nothing depends on them currently. --- std/c/darwin.zig | 22 ++++++++++++++++++++-- std/c/index.zig | 2 +- std/os/time.zig | 2 -- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/std/c/darwin.zig b/std/c/darwin.zig index 86c5e4828e..4f0ea4a02b 100644 --- a/std/c/darwin.zig +++ b/std/c/darwin.zig @@ -73,8 +73,8 @@ pub const sockaddr_in6 = extern struct { }; pub const timeval = extern struct { - tv_sec: isize, - tv_usec: isize, + tv_sec: c_long, + tv_usec: i32, }; pub const timezone = extern struct { @@ -176,6 +176,24 @@ pub const kevent64_s = extern struct { ext: [2]u64, }; +pub const mach_port_t = c_uint; +pub const clock_serv_t = mach_port_t; +pub const clock_res_t = c_int; +pub const mach_port_name_t = natural_t; +pub const natural_t = c_uint; +pub const mach_timespec_t = extern struct { + tv_sec: c_uint, + tv_nsec: clock_res_t, +}; +pub const kern_return_t = c_int; +pub const host_t = mach_port_t; +pub const CALENDAR_CLOCK = 1; + +pub extern fn mach_host_self() mach_port_t; +pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t; +pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t; +pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t; + // sys/types.h on macos uses #pragma pack() 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. diff --git a/std/c/index.zig b/std/c/index.zig index 4aab39d931..058d879c09 100644 --- a/std/c/index.zig +++ b/std/c/index.zig @@ -44,7 +44,7 @@ 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(tv: ?*timeval, tz: ?*timezone) 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; diff --git a/std/os/time.zig b/std/os/time.zig index 304f65206a..4b11a69376 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -79,8 +79,6 @@ fn milliTimestampWindows() u64 { } fn milliTimestampDarwin() u64 { - //Sources suggest MacOS 10.12 has support for - // posix clock_gettime. var tv: darwin.timeval = undefined; var err = darwin.gettimeofday(&tv, null); debug.assert(err == 0); From bfc1772d8ead9e8fcde0a315411ddcd040cc3d28 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Feb 2019 12:22:21 -0500 Subject: [PATCH 128/218] fixups --- CMakeLists.txt | 31 ++++---- std/fmt/index.zig | 2 - std/index.zig | 2 + std/mutex.zig | 61 +++------------- std/os/windows/kernel32.zig | 14 ++-- std/statically_initialized_mutex.zig | 105 +++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 73 deletions(-) create mode 100644 std/statically_initialized_mutex.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 3841519f29..4dd6a1dcfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -454,10 +454,10 @@ set(ZIG_STD_FILES "crypto/hmac.zig" "crypto/index.zig" "crypto/md5.zig" + "crypto/poly1305.zig" "crypto/sha1.zig" "crypto/sha2.zig" "crypto/sha3.zig" - "crypto/poly1305.zig" "crypto/x25519.zig" "cstr.zig" "debug/failing_allocator.zig" @@ -566,9 +566,9 @@ set(ZIG_STD_FILES "math/tan.zig" "math/tanh.zig" "math/trunc.zig" + "mem.zig" "meta/index.zig" "meta/trait.zig" - "mem.zig" "mutex.zig" "net.zig" "os/child_process.zig" @@ -576,16 +576,16 @@ set(ZIG_STD_FILES "os/darwin/errno.zig" "os/epoch.zig" "os/file.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/arm64.zig" "os/linux/errno.zig" "os/linux/index.zig" "os/linux/vdso.zig" "os/linux/x86_64.zig" - "os/linux/arm64.zig" - "os/freebsd/errno.zig" - "os/freebsd/index.zig" "os/path.zig" "os/time.zig" "os/uefi.zig" @@ -612,6 +612,16 @@ set(ZIG_STD_FILES "special/compiler_rt/comparetf2.zig" "special/compiler_rt/divti3.zig" "special/compiler_rt/extendXfYf2.zig" + "special/compiler_rt/fixdfdi.zig" + "special/compiler_rt/fixdfsi.zig" + "special/compiler_rt/fixdfti.zig" + "special/compiler_rt/fixint.zig" + "special/compiler_rt/fixsfdi.zig" + "special/compiler_rt/fixsfsi.zig" + "special/compiler_rt/fixsfti.zig" + "special/compiler_rt/fixtfdi.zig" + "special/compiler_rt/fixtfsi.zig" + "special/compiler_rt/fixtfti.zig" "special/compiler_rt/fixuint.zig" "special/compiler_rt/fixunsdfdi.zig" "special/compiler_rt/fixunsdfsi.zig" @@ -622,16 +632,6 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" - "special/compiler_rt/fixint.zig" - "special/compiler_rt/fixdfdi.zig" - "special/compiler_rt/fixdfsi.zig" - "special/compiler_rt/fixdfti.zig" - "special/compiler_rt/fixsfdi.zig" - "special/compiler_rt/fixsfsi.zig" - "special/compiler_rt/fixsfti.zig" - "special/compiler_rt/fixtfdi.zig" - "special/compiler_rt/fixtfsi.zig" - "special/compiler_rt/fixtfti.zig" "special/compiler_rt/floattidf.zig" "special/compiler_rt/floattisf.zig" "special/compiler_rt/floattitf.zig" @@ -656,6 +656,7 @@ set(ZIG_STD_FILES "special/panic.zig" "special/test_runner.zig" "spinlock.zig" + "statically_initialized_mutex.zig" "unicode.zig" "zig/ast.zig" "zig/index.zig" diff --git a/std/fmt/index.zig b/std/fmt/index.zig index b010072273..6097a12c23 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -982,13 +982,11 @@ test "fmt.format" { context = BufPrintContext{ .remaining = buf1[0..] }; try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); res = buf1[0 .. buf1.len - context.remaining.len]; - debug.warn("{}\n", res); assert(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]; - debug.warn("{}\n", res); assert(mem.eql(u8, res, "1100")); } { diff --git a/std/index.zig b/std/index.zig index 33eec14b0e..80d1e46bb6 100644 --- a/std/index.zig +++ b/std/index.zig @@ -9,6 +9,7 @@ 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 StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; pub const SegmentedList = @import("segmented_list.zig").SegmentedList; pub const SpinLock = @import("spinlock.zig").SpinLock; @@ -55,6 +56,7 @@ test "std" { _ = @import("hash_map.zig"); _ = @import("linked_list.zig"); _ = @import("mutex.zig"); + _ = @import("statically_initialized_mutex.zig"); _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); diff --git a/std/mutex.zig b/std/mutex.zig index 2885a99ed7..723581cbef 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -9,6 +9,9 @@ const windows = std.os.windows; /// Lock may be held only once. If the same thread /// tries to acquire the same mutex twice, it deadlocks. +/// This type must be initialized at runtime, and then deinitialized when no +/// longer needed, to free resources. +/// If you need static initialization, use std.StaticallyInitializedMutex. /// The Linux implementation is based on mutex3 from /// https://www.akkadia.org/drepper/futex.pdf pub const Mutex = switch(builtin.os) { @@ -60,57 +63,15 @@ pub const Mutex = switch(builtin.os) { return Held { .mutex = self }; } }, - builtin.Os.windows => struct { - - lock: windows.CRITICAL_SECTION, - init_once: windows.RTL_RUN_ONCE, - - pub const Held = struct { - mutex: *Mutex, - - pub fn release(self: Held) void { - windows.LeaveCriticalSection(&self.mutex.lock); - } - }; - - pub fn init() Mutex { - return Mutex { - .lock = undefined, - .init_once = windows.INIT_ONCE_STATIC_INIT, - }; - } - - extern fn initCriticalSection( - InitOnce: *windows.RTL_RUN_ONCE, - Parameter: ?windows.PVOID, - Context: ?windows.PVOID - ) windows.BOOL { - var lock = @ptrCast( - *windows.CRITICAL_SECTION, - @alignCast(@alignOf(*windows.CRITICAL_SECTION), Context.?) - ); - windows.InitializeCriticalSection(lock); - return windows.TRUE; - } - - pub fn deinit(self: *Mutex) void { - windows.DeleteCriticalSection(&self.lock); - } - - pub fn acquire(self: *Mutex) Held { - if (windows.InitOnceExecuteOnce( - &self.init_once, - initCriticalSection, - null, @ptrCast(?windows.PVOID, self) - ) == windows.FALSE) { - unreachable; - } - windows.EnterCriticalSection(&self.lock); - return Held { .mutex = self }; - } - }, + // TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a + // better implementation of this. The problem is we need the init() function to have access to + // the address of the CRITICAL_SECTION, and then have it not move. + builtin.Os.windows => std.StaticallyInitializedMutex, else => struct { - /// TODO better implementation than spin lock + /// TODO better implementation than spin lock. + /// When changing this, one must also change the corresponding + /// std.StaticallyInitializedMutex code, since it aliases this type, + /// under the assumption that it works both statically and at runtime. lock: SpinLock, pub const Held = struct { diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 7a6126133a..66b9552c5f 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -253,15 +253,17 @@ pub const RTL_CRITICAL_SECTION = extern struct { }; pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; +pub const INIT_ONCE = RTL_RUN_ONCE; +pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; -pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *RTL_RUN_ONCE, InitFn: PINIT_ONCE_FN, Context: ?PVOID, Parameter: ?LPVOID) BOOL; +pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; -pub const PINIT_ONCE_FN = ?extern fn(InitOnce: *RTL_RUN_ONCE, Parameter: ?PVOID, Context: ?PVOID) 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: ?PVOID, + Ptr: ?*c_void, }; -pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE { - .Ptr = null, -}; \ No newline at end of file +pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE { + .Ptr = null, +}; diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig new file mode 100644 index 0000000000..dd875eeaf9 --- /dev/null +++ b/std/statically_initialized_mutex.zig @@ -0,0 +1,105 @@ +const std = @import("index.zig"); +const builtin = @import("builtin"); +const AtomicOrder = builtin.AtomicOrder; +const AtomicRmwOp = builtin.AtomicRmwOp; +const assert = std.debug.assert; +const windows = std.os.windows; + +/// Lock may be held only once. If the same thread +/// tries to acquire the same mutex twice, it deadlocks. +/// This type is intended to be initialized statically. If you don't +/// require static initialization, use std.Mutex. +/// 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) { + builtin.Os.linux => std.Mutex, + builtin.Os.windows => struct { + lock: windows.CRITICAL_SECTION, + init_once: windows.RTL_RUN_ONCE, + + pub const Held = struct { + mutex: *StaticallyInitializedMutex, + + pub fn release(self: Held) void { + windows.LeaveCriticalSection(&self.mutex.lock); + } + }; + + pub fn init() StaticallyInitializedMutex { + return StaticallyInitializedMutex { + .lock = undefined, + .init_once = windows.INIT_ONCE_STATIC_INIT, + }; + } + + extern fn initCriticalSection( + InitOnce: *windows.RTL_RUN_ONCE, + Parameter: ?*c_void, + Context: ?*c_void, + ) windows.BOOL { + const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter)); + windows.InitializeCriticalSection(lock); + return windows.TRUE; + } + + /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better + /// implementation of a runtime initialized mutex, remove this function. + pub fn deinit(self: *StaticallyInitializedMutex) void { + assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0); + windows.DeleteCriticalSection(&self.lock); + } + + 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 }; + } + }, + else => std.Mutex, +}; + +test "std.StaticallyInitializedMutex" { + const TestContext = struct { + data: i128, + + const TestContext = @This(); + const incr_count = 10000; + + var mutex = StaticallyInitializedMutex.init(); + + fn worker(ctx: *TestContext) void { + var i: usize = 0; + while (i != TestContext.incr_count) : (i += 1) { + const held = mutex.acquire(); + defer held.release(); + + ctx.data += 1; + } + } + }; + + var direct_allocator = std.heap.DirectAllocator.init(); + defer direct_allocator.deinit(); + + var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024); + defer direct_allocator.allocator.free(plenty_of_memory); + + var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory); + var a = &fixed_buffer_allocator.allocator; + + + var context = TestContext{ + .data = 0, + }; + + const thread_count = 10; + var threads: [thread_count]*std.os.Thread = undefined; + for (threads) |*t| { + t.* = try std.os.spawnThread(&context, TestContext.worker); + } + for (threads) |t| + t.wait(); + + std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); +} From ae1ebe09b7c1258bfa8de37244fd9b510b1447a4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Feb 2019 14:06:51 -0500 Subject: [PATCH 129/218] add compile errror for @bitCast when bit counts mismatch fixes invalid LLVM IR from previous commit --- src/ir.cpp | 14 +++++++++++-- std/io.zig | 46 ++++++++++++++++++++++------------------- test/compile_errors.zig | 9 ++++++++ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index d5152f3c85..dc700c4178 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20580,10 +20580,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, dest_type))) + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, src_type))) + if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; if (get_codegen_ptr_type(src_type) != nullptr) { @@ -20646,6 +20646,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); + uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); + if (dest_size_bits != src_size_bits) { + ir_add_error(ira, &instruction->base, + buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", + buf_ptr(&dest_type->name), dest_size_bits, + buf_ptr(&src_type->name), src_size_bits)); + return ira->codegen->invalid_instruction; + } + if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) diff --git a/std/io.zig b/std/io.zig index 57f2ef3df5..46625cd34b 100644 --- a/std/io.zig +++ b/std/io.zig @@ -503,13 +503,13 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { /// containing them in the least significant end. The number of bits successfully /// read is placed in `out_bits`, as reaching the end of the stream is not an error. pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U { - debug.assert(trait.isUnsignedInt(U)); + comptime assert(trait.isUnsignedInt(U)); //by extending the buffer to a minimum of u8 we can cover a number of edge cases // related to shifting and casting. const u_bit_count = comptime meta.bitCount(U); const buf_bit_count = bc: { - debug.assert(u_bit_count >= bits); + assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; const Buf = @IntType(false, buf_bit_count); @@ -664,7 +664,7 @@ test "io.SliceOutStream" { const stream = &slice_stream.stream; try stream.print("{}{}!", "Hello", "World"); - debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); + debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); } var null_out_stream_state = NullOutStream.init(); @@ -726,7 +726,7 @@ test "io.CountingOutStream" { const bytes = "yay" ** 10000; stream.write(bytes) catch unreachable; - debug.assert(counting_stream.bytes_written == bytes.len); + debug.assertOrPanic(counting_stream.bytes_written == bytes.len); } pub fn BufferedOutStream(comptime Error: type) type { @@ -835,13 +835,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { if (bits == 0) return; const U = @typeOf(value); - debug.assert(trait.isUnsignedInt(U)); + comptime assert(trait.isUnsignedInt(U)); //by extending the buffer to a minimum of u8 we can cover a number of edge cases // related to shifting and casting. const u_bit_count = comptime meta.bitCount(U); const buf_bit_count = bc: { - debug.assert(u_bit_count >= bits); + assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; const Buf = @IntType(false, buf_bit_count); @@ -1013,10 +1013,10 @@ test "io.readLineFrom" { ); const stream = &mem_stream.stream; - debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); - debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); + debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); + debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); - debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); + debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); } pub fn readLineSlice(slice: []u8) ![]u8 { @@ -1044,7 +1044,7 @@ test "io.readLineSliceFrom" { ); const stream = &mem_stream.stream; - debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); + debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); } @@ -1057,7 +1057,7 @@ test "io.readLineSliceFrom" { /// which will be called when the deserializer is used to deserialize /// that type. It will pass a pointer to the type instance to deserialize /// into and a pointer to the deserializer struct. -pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { +pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type { return struct { const Self = @This(); @@ -1079,9 +1079,9 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { - debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); - const u8_bit_count = comptime meta.bitCount(u8); + const u8_bit_count = 8; const t_bit_count = comptime meta.bitCount(T); const U = @IntType(false, t_bit_count); @@ -1097,13 +1097,17 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ const read_size = try self.in_stream.read(buffer[0..]); if (read_size < int_size) return error.EndOfStream; - if (int_size == 1) return @bitCast(T, buffer[0]); + if (int_size == 1) { + if (t_bit_count == 8) return @bitCast(T, buffer[0]); + const PossiblySignedByte = @IntType(T.is_signed, 8); + return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); + } var result = U(0); for (buffer) |byte, i| { switch (endian) { builtin.Endian.Big => { - result = (result << @intCast(u4, u8_bit_count)) | byte; + result = (result << u8_bit_count) | byte; }, builtin.Endian.Little => { result |= U(byte) << @intCast(Log2U, u8_bit_count * i); @@ -1118,12 +1122,12 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ // see: #1315 fn setTag(ptr: var, tag: var) void { const T = @typeOf(ptr); - comptime debug.assert(trait.isPtrTo(builtin.TypeId.Union)(T)); + comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T)); const U = meta.Child(T); const info = @typeInfo(U).Union; if (info.tag_type) |TagType| { - debug.assert(TagType == @typeOf(tag)); + comptime assert(TagType == @typeOf(tag)); var ptr_tag = ptr: { if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr); @@ -1151,7 +1155,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ /// Deserializes data into the type pointed to by `ptr` pub fn deserializeInto(self: *Self, ptr: var) !void { const T = @typeOf(ptr); - debug.assert(trait.is(builtin.TypeId.Pointer)(T)); + comptime assert(trait.is(builtin.TypeId.Pointer)(T)); if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) { for (ptr) |*v| @@ -1159,7 +1163,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ return; } - comptime debug.assert(trait.isSingleItemPtr(T)); + comptime assert(trait.isSingleItemPtr(T)); const C = comptime meta.Child(T); const child_type_id = @typeId(C); @@ -1266,7 +1270,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ /// which will be called when the serializer is used to serialize that type. It will /// pass a const pointer to the type instance to be serialized and a pointer /// to the serializer struct. -pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { +pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type { return struct { const Self = @This(); @@ -1288,7 +1292,7 @@ pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) fn serializeInt(self: *Self, value: var) !void { const T = @typeOf(value); - debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); const t_bit_count = comptime meta.bitCount(T); const u8_bit_count = comptime meta.bitCount(u8); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f2a2ba2641..74602b77ff 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "@bitCast same size but bit count mismatch", + \\export fn entry(byte: u8) 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", + ); + cases.add( "attempted `&&`", \\export fn entry(a: bool, b: bool) i32 { From 8bedb10939b511e39787b2693249d2d3e8102854 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 1 Feb 2019 03:12:56 -0800 Subject: [PATCH 130/218] Fix runtime assignment to comptime aggregate field This was causing a segfault --- src/ir.cpp | 6 ++++-- test/compile_errors.zig | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index dc700c4178..d676e7a6c5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16533,7 +16533,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) + || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || !type_has_bits(casted_field_value->value.type)) { @@ -16584,7 +16585,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstructionStructInitField *new_fields = allocate(actual_field_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) + || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 74602b77ff..30d9ca5d70 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5367,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", ); + + cases.add( + "runtime assignment to comptime struct type", + \\const Foo = struct { + \\ Bar: u8, + \\ Baz: type, + \\}; + \\export fn f() void { + \\ var x: u8 = 0; + \\ const foo = Foo { .Bar = x, .Baz = u8 }; + \\} + , + ".tmp_source.zig:7:30: error: unable to evaluate constant expression", + ); + + cases.add( + "runtime assignment to comptime union type", + \\const Foo = union { + \\ Bar: u8, + \\ Baz: type, + \\}; + \\export fn f() void { + \\ var x: u8 = 0; + \\ const foo = Foo { .Bar = x }; + \\} + , + ".tmp_source.zig:7:30: error: unable to evaluate constant expression", + ); } From 9b8e23934bc87f1fd6a42cdfdd551212994b6e58 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Feb 2019 17:49:29 -0500 Subject: [PATCH 131/218] introduce --single-threaded build option closes #1764 This adds another boolean to the test matrix; hopefully it does not inflate the time too much. std.event.Loop does not work with this option yet. See #1908 --- doc/langref.html.in | 19 +++++++ src/all_types.hpp | 1 + src/codegen.cpp | 4 ++ src/main.cpp | 6 +++ std/atomic/queue.zig | 42 ++++++++++----- std/atomic/stack.zig | 78 +++++++++++++++++++--------- std/event/channel.zig | 3 ++ std/event/future.zig | 3 ++ std/event/group.zig | 3 ++ std/event/lock.zig | 3 ++ std/event/loop.zig | 22 ++++++++ std/event/net.zig | 3 ++ std/event/rwlock.zig | 3 ++ std/mutex.zig | 66 ++++++++++++++++------- std/os/index.zig | 1 + std/os/test.zig | 4 ++ std/statically_initialized_mutex.zig | 21 +++++--- test/tests.zig | 43 ++++++++------- 18 files changed, 244 insertions(+), 81 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index e192dbbf76..144c8571c4 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6714,6 +6714,25 @@ pub fn build(b: *Builder) void { {#header_close#} {#see_also|Compile Variables|Zig Build System|Undefined Behavior#} {#header_close#} + + {#header_open|Single Threaded Builds#} +

Zig has a compile option --single-threaded which has the following effects: +

    +
  • {#link|@atomicLoad#} is emitted as a normal load.
  • +
  • {#link|@atomicRmw#} is emitted as a normal memory load, modify, store.
  • +
  • {#link|@fence#} becomes a no-op.
  • +
  • Variables which have Thread Local Storage instead become globals. TODO thread local variables + are not implemented yet.
  • +
  • The overhead of {#link|Coroutines#} becomes equivalent to function call overhead. + TODO: please note this will not be implemented until the upcoming Coroutine Rewrite
  • +
  • The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#} + and therefore various userland APIs which read this variable become more efficient. + For example {#syntax#}std.Mutex{#endsyntax#} becomes + an empty data structure and all of its functions become no-ops.
  • +
+

+ {#header_close#} + {#header_open|Undefined Behavior#}

Zig has many instances of undefined behavior. If undefined behavior is diff --git a/src/all_types.hpp b/src/all_types.hpp index f6fe72891d..3fc6772b31 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1808,6 +1808,7 @@ struct CodeGen { bool is_static; bool strip_debug_symbols; bool is_test_build; + bool is_single_threaded; bool is_native_target; bool linker_rdynamic; bool no_rosegment_workaround; diff --git a/src/codegen.cpp b/src/codegen.cpp index e2576f5335..b73fda59d1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -118,6 +118,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out g->string_literals_table.init(16); g->type_info_cache.init(32); g->is_test_build = false; + g->is_single_threaded = false; buf_resize(&g->global_asm, 0); for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { @@ -7377,6 +7378,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const endian = %s;\n", endian_str); } buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); + buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch); buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ); @@ -7411,6 +7413,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_buf(&cache_hash, compiler_id); cache_int(&cache_hash, g->build_mode); cache_bool(&cache_hash, g->is_test_build); + cache_bool(&cache_hash, g->is_single_threaded); cache_int(&cache_hash, g->zig_target.arch.arch); cache_int(&cache_hash, g->zig_target.arch.sub_arch); cache_int(&cache_hash, g->zig_target.vendor); @@ -8329,6 +8332,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->is_static); cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); + cache_bool(ch, g->is_single_threaded); cache_bool(ch, g->is_native_target); cache_bool(ch, g->linker_rdynamic); cache_bool(ch, g->no_rosegment_workaround); diff --git a/src/main.cpp b/src/main.cpp index fd8e3db2fa..81f49089be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,6 +59,7 @@ static int print_full_usage(const char *arg0) { " --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" + " --single-threaded source may assume it is only used single-threaded\n" " --static output will be statically linked\n" " --strip exclude debug symbols\n" " --target-arch [name] specify target architecture\n" @@ -393,6 +394,7 @@ int main(int argc, char **argv) { bool no_rosegment_workaround = false; bool system_linker_hack = false; TargetSubsystem subsystem = TargetSubsystemAuto; + bool is_single_threaded = false; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -550,6 +552,8 @@ int main(int argc, char **argv) { disable_pic = true; } else if (strcmp(arg, "--system-linker-hack") == 0) { system_linker_hack = true; + } else if (strcmp(arg, "--single-threaded") == 0) { + is_single_threaded = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { @@ -816,6 +820,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); + g->is_single_threaded = is_single_threaded; Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -889,6 +894,7 @@ int main(int argc, char **argv) { codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); codegen_set_is_test(g, cmd == CmdTest); + g->is_single_threaded = is_single_threaded; codegen_set_linker_script(g, linker_script); if (each_lib_rpath) codegen_set_each_lib_rpath(g, each_lib_rpath); diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 1aab4c32de..6c61bcc048 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -170,20 +170,36 @@ test "std.atomic.Queue" { .get_count = 0, }; - var putters: [put_thread_count]*std.os.Thread = undefined; - for (putters) |*t| { - t.* = try std.os.spawnThread(&context, startPuts); - } - var getters: [put_thread_count]*std.os.Thread = undefined; - for (getters) |*t| { - t.* = try std.os.spawnThread(&context, startGets); - } + if (builtin.single_threaded) { + { + var i: usize = 0; + while (i < put_thread_count) : (i += 1) { + std.debug.assertOrPanic(startPuts(&context) == 0); + } + } + context.puts_done = 1; + { + var i: usize = 0; + while (i < put_thread_count) : (i += 1) { + std.debug.assertOrPanic(startGets(&context) == 0); + } + } + } else { + var putters: [put_thread_count]*std.os.Thread = undefined; + for (putters) |*t| { + t.* = try std.os.spawnThread(&context, startPuts); + } + var getters: [put_thread_count]*std.os.Thread = undefined; + for (getters) |*t| { + t.* = try std.os.spawnThread(&context, startGets); + } - for (putters) |t| - t.wait(); - _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); - for (getters) |t| - t.wait(); + for (putters) |t| + t.wait(); + _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); + for (getters) |t| + t.wait(); + } if (context.put_sum != context.get_sum) { std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index b69a93733c..1e4981353b 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -4,10 +4,13 @@ const AtomicOrder = builtin.AtomicOrder; /// Many reader, many writer, non-allocating, thread-safe /// Uses a spinlock to protect push() and pop() +/// When building in single threaded mode, this is a simple linked list. pub fn Stack(comptime T: type) type { return struct { root: ?*Node, - lock: u8, + lock: @typeOf(lock_init), + + const lock_init = if (builtin.single_threaded) {} else u8(0); pub const Self = @This(); @@ -19,7 +22,7 @@ pub fn Stack(comptime T: type) type { pub fn init() Self { return Self{ .root = null, - .lock = 0, + .lock = lock_init, }; } @@ -31,20 +34,31 @@ pub fn Stack(comptime T: type) type { } pub fn push(self: *Self, node: *Node) void { - while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} - defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); + if (builtin.single_threaded) { + node.next = self.root; + self.root = node; + } else { + while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} + defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); - node.next = self.root; - self.root = node; + node.next = self.root; + self.root = node; + } } pub fn pop(self: *Self) ?*Node { - while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} - defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); + if (builtin.single_threaded) { + const root = self.root orelse return null; + self.root = root.next; + return root; + } else { + while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {} + defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1); - const root = self.root orelse return null; - self.root = root.next; - return root; + const root = self.root orelse return null; + self.root = root.next; + return root; + } } pub fn isEmpty(self: *Self) bool { @@ -90,20 +104,36 @@ test "std.atomic.stack" { .get_count = 0, }; - var putters: [put_thread_count]*std.os.Thread = undefined; - for (putters) |*t| { - t.* = try std.os.spawnThread(&context, startPuts); - } - var getters: [put_thread_count]*std.os.Thread = undefined; - for (getters) |*t| { - t.* = try std.os.spawnThread(&context, startGets); - } + if (builtin.single_threaded) { + { + var i: usize = 0; + while (i < put_thread_count) : (i += 1) { + std.debug.assertOrPanic(startPuts(&context) == 0); + } + } + context.puts_done = 1; + { + var i: usize = 0; + while (i < put_thread_count) : (i += 1) { + std.debug.assertOrPanic(startGets(&context) == 0); + } + } + } else { + var putters: [put_thread_count]*std.os.Thread = undefined; + for (putters) |*t| { + t.* = try std.os.spawnThread(&context, startPuts); + } + var getters: [put_thread_count]*std.os.Thread = undefined; + for (getters) |*t| { + t.* = try std.os.spawnThread(&context, startGets); + } - for (putters) |t| - t.wait(); - _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); - for (getters) |t| - t.wait(); + for (putters) |t| + t.wait(); + _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); + for (getters) |t| + t.wait(); + } if (context.put_sum != context.get_sum) { std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum); diff --git a/std/event/channel.zig b/std/event/channel.zig index 133ce1c69c..f04ad1604e 100644 --- a/std/event/channel.zig +++ b/std/event/channel.zig @@ -319,6 +319,9 @@ pub fn Channel(comptime T: type) type { } test "std.event.Channel" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/event/future.zig b/std/event/future.zig index d61768b198..55ed01046d 100644 --- a/std/event/future.zig +++ b/std/event/future.zig @@ -84,6 +84,9 @@ pub fn Future(comptime T: type) type { } test "std.event.Future" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/event/group.zig b/std/event/group.zig index 9f2687a5b3..0e9c2d9655 100644 --- a/std/event/group.zig +++ b/std/event/group.zig @@ -121,6 +121,9 @@ pub fn Group(comptime ReturnType: type) type { } test "std.event.Group" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/event/lock.zig b/std/event/lock.zig index 46e0d13468..01978e1909 100644 --- a/std/event/lock.zig +++ b/std/event/lock.zig @@ -122,6 +122,9 @@ pub const Lock = struct { }; test "std.event.Lock" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/event/loop.zig b/std/event/loop.zig index 43965e8293..d5228db604 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -97,6 +97,7 @@ pub const Loop = struct { /// TODO copy elision / named return values so that the threads referencing *Loop /// have the correct pointer value. pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void { + if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode"); const core_count = try os.cpuCount(allocator); return self.initInternal(allocator, core_count); } @@ -201,6 +202,11 @@ pub const Loop = struct { self.os_data.fs_thread.wait(); } + if (builtin.single_threaded) { + assert(extra_thread_count == 0); + return; + } + var extra_thread_index: usize = 0; errdefer { // writing 8 bytes to an eventfd cannot fail @@ -301,6 +307,11 @@ pub const Loop = struct { self.os_data.fs_thread.wait(); } + if (builtin.single_threaded) { + assert(extra_thread_count == 0); + return; + } + var extra_thread_index: usize = 0; errdefer { _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable; @@ -338,6 +349,11 @@ pub const Loop = struct { self.available_eventfd_resume_nodes.push(eventfd_node); } + if (builtin.single_threaded) { + assert(extra_thread_count == 0); + return; + } + var extra_thread_index: usize = 0; errdefer { var i: usize = 0; @@ -845,6 +861,9 @@ pub const Loop = struct { }; test "std.event.Loop - basic" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); @@ -858,6 +877,9 @@ test "std.event.Loop - basic" { } test "std.event.Loop - call" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/event/net.zig b/std/event/net.zig index 6838704084..9dac6aa566 100644 --- a/std/event/net.zig +++ b/std/event/net.zig @@ -269,6 +269,9 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File { } test "listen on a port, send bytes, receive bytes" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + if (builtin.os != builtin.Os.linux) { // TODO build abstractions for other operating systems return error.SkipZigTest; diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig index 5d48ea893e..f272ac71ea 100644 --- a/std/event/rwlock.zig +++ b/std/event/rwlock.zig @@ -211,6 +211,9 @@ pub const RwLock = struct { }; test "std.event.RwLock" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + var da = std.heap.DirectAllocator.init(); defer da.deinit(); diff --git a/std/mutex.zig b/std/mutex.zig index 723581cbef..54173fa38a 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -14,7 +14,36 @@ const windows = std.os.windows; /// If you need static initialization, use std.StaticallyInitializedMutex. /// The Linux implementation is based on mutex3 from /// https://www.akkadia.org/drepper/futex.pdf -pub const Mutex = switch(builtin.os) { +/// When an application is built in single threaded release mode, all the functions are +/// no-ops. In single threaded debug mode, there is deadlock detection. +pub const Mutex = if (builtin.single_threaded) + struct { + lock: @typeOf(lock_init), + + const lock_init = if (std.debug.runtime_safety) false else {}; + + pub const Held = struct { + mutex: *Mutex, + + pub fn release(self: Held) void { + if (std.debug.runtime_safety) { + self.mutex.lock = false; + } + } + }; + pub fn init() Mutex { + return Mutex{ .lock = lock_init }; + } + pub fn deinit(self: *Mutex) void {} + + pub fn acquire(self: *Mutex) Held { + if (std.debug.runtime_safety and self.lock) { + @panic("deadlock detected"); + } + return Held{ .mutex = self }; + } + } +else switch (builtin.os) { builtin.Os.linux => struct { /// 0: unlocked /// 1: locked, no waiters @@ -39,9 +68,7 @@ pub const Mutex = switch(builtin.os) { }; pub fn init() Mutex { - return Mutex { - .lock = 0, - }; + return Mutex{ .lock = 0 }; } pub fn deinit(self: *Mutex) void {} @@ -60,7 +87,7 @@ pub const Mutex = switch(builtin.os) { } c = @atomicRmw(i32, &self.lock, AtomicRmwOp.Xchg, 2, AtomicOrder.Acquire); } - return Held { .mutex = self }; + return Held{ .mutex = self }; } }, // TODO once https://github.com/ziglang/zig/issues/287 (copy elision) is solved, we can make a @@ -78,21 +105,19 @@ pub const Mutex = switch(builtin.os) { mutex: *Mutex, pub fn release(self: Held) void { - SpinLock.Held.release(SpinLock.Held { .spinlock = &self.mutex.lock }); + SpinLock.Held.release(SpinLock.Held{ .spinlock = &self.mutex.lock }); } }; pub fn init() Mutex { - return Mutex { - .lock = SpinLock.init(), - }; + return Mutex{ .lock = SpinLock.init() }; } pub fn deinit(self: *Mutex) void {} pub fn acquire(self: *Mutex) Held { _ = self.lock.acquire(); - return Held { .mutex = self }; + return Held{ .mutex = self }; } }, }; @@ -122,15 +147,20 @@ test "std.Mutex" { .data = 0, }; - const thread_count = 10; - var threads: [thread_count]*std.os.Thread = undefined; - for (threads) |*t| { - t.* = try std.os.spawnThread(&context, worker); - } - for (threads) |t| - t.wait(); + if (builtin.single_threaded) { + worker(&context); + std.debug.assertOrPanic(context.data == TestContext.incr_count); + } else { + const thread_count = 10; + var threads: [thread_count]*std.os.Thread = undefined; + for (threads) |*t| { + t.* = try std.os.spawnThread(&context, worker); + } + for (threads) |t| + t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + } } fn worker(ctx: *TestContext) void { diff --git a/std/os/index.zig b/std/os/index.zig index 78d543583d..75abe3bbde 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -3013,6 +3013,7 @@ pub const SpawnThreadError = error{ /// 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; diff --git a/std/os/test.zig b/std/os/test.zig index 5142920687..f14cf47786 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -40,6 +40,8 @@ fn testThreadIdFn(thread_id: *os.Thread.Id) void { } test "std.os.Thread.getCurrentId" { + if (builtin.single_threaded) return error.SkipZigTest; + var thread_current_id: os.Thread.Id = undefined; const thread = try os.spawnThread(&thread_current_id, testThreadIdFn); const thread_id = thread.handle(); @@ -53,6 +55,8 @@ test "std.os.Thread.getCurrentId" { } test "spawn threads" { + if (builtin.single_threaded) return error.SkipZigTest; + var shared_ctx: i32 = 1; const thread1 = try std.os.spawnThread({}, start1); diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig index dd875eeaf9..37582d49c1 100644 --- a/std/statically_initialized_mutex.zig +++ b/std/statically_initialized_mutex.zig @@ -93,13 +93,18 @@ test "std.StaticallyInitializedMutex" { .data = 0, }; - const thread_count = 10; - var threads: [thread_count]*std.os.Thread = undefined; - for (threads) |*t| { - t.* = try std.os.spawnThread(&context, TestContext.worker); - } - for (threads) |t| - t.wait(); + if (builtin.single_threaded) { + TestContext.worker(&context); + std.debug.assertOrPanic(context.data == TestContext.incr_count); + } else { + const thread_count = 10; + var threads: [thread_count]*std.os.Thread = undefined; + for (threads) |*t| { + t.* = try std.os.spawnThread(&context, TestContext.worker); + } + for (threads) |t| + t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + } } diff --git a/test/tests.zig b/test/tests.zig index 1ca06b4b34..73d4644d18 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -163,25 +163,32 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons for (test_targets) |test_target| { const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch); for (modes) |mode| { - for ([]bool{ - false, - true, - }) |link_libc| { - if (link_libc and !is_native) { - // don't assume we have a cross-compiling libc set up - continue; + for ([]bool{ false, true }) |link_libc| { + for ([]bool{ false, true }) |single_threaded| { + if (link_libc and !is_native) { + // don't assume we have a cross-compiling libc set up + continue; + } + const these_tests = b.addTest(root_src); + these_tests.setNamePrefix(b.fmt( + "{}-{}-{}-{}-{}-{} ", + name, + @tagName(test_target.os), + @tagName(test_target.arch), + @tagName(mode), + if (link_libc) "c" else "bare", + if (single_threaded) "single" else "multi", + )); + these_tests.setFilter(test_filter); + these_tests.setBuildMode(mode); + if (!is_native) { + these_tests.setTarget(test_target.arch, test_target.os, test_target.environ); + } + if (link_libc) { + these_tests.linkSystemLibrary("c"); + } + step.dependOn(&these_tests.step); } - const these_tests = b.addTest(root_src); - these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare")); - these_tests.setFilter(test_filter); - these_tests.setBuildMode(mode); - if (!is_native) { - these_tests.setTarget(test_target.arch, test_target.os, test_target.environ); - } - if (link_libc) { - these_tests.linkSystemLibrary("c"); - } - step.dependOn(&these_tests.step); } } } From c90c256868a80cd35e9ba679ba082330592620c9 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Sat, 2 Feb 2019 13:57:53 -0800 Subject: [PATCH 132/218] Fix slice concatenation This was causing an underflow error --- src/ir.cpp | 33 ++++++++++++--------------------- test/stage1/behavior/eval.zig | 4 ++-- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index d676e7a6c5..3d3c501df3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12369,7 +12369,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; - op1_array_end = bigint_as_unsigned(&len_val->data.x_bigint); + op1_array_end = op1_array_index + bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op1, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); @@ -12379,13 +12379,9 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i ConstExprValue *op2_array_val; size_t op2_array_index; size_t op2_array_end; + bool op2_type_valid; if (op2_type->id == ZigTypeIdArray) { - if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = op2_type->data.array.child_type == child_type; op2_array_val = op2_val; op2_array_index = 0; op2_array_end = op2_array_val->type->data.array.len; @@ -12394,35 +12390,30 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && op2_val->data.x_ptr.data.base_array.is_cstr) { - if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8; op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; op2_array_end = op2_array_val->type->data.array.len - 1; } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; - if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = ptr_type->data.pointer.child_type == child_type; ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - op2_array_end = op2_array_val->type->data.array.len; ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; - op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); + op2_array_end = op2_array_index + bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } + if (!op2_type_valid) { + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + buf_ptr(&child_type->name), + buf_ptr(&op2->value.type->name))); + return ira->codegen->invalid_instruction; + } // The type of result is populated in the following if blocks IrInstruction *result = ir_const(ira, &instruction->base, nullptr); diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 2d8494eb0b..3e8af0524f 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -728,8 +728,8 @@ test "comptime pointer cast array and then slice" { test "slice bounds in comptime concatenation" { const bs = comptime blk: { - const b = c"11"; - break :blk b[0..1]; + const b = c"........1........"; + break :blk b[8..9]; }; const str = "" ++ bs; assertOrPanic(str.len == 1); From dfbc063f79dc1358208216b466c1bf8c44baa430 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 3 Feb 2019 16:13:28 -0500 Subject: [PATCH 133/218] `std.mem.Allocator.create` replaced with better API `std.mem.Allocator.createOne` is renamed to `std.mem.Allocator.create`. The problem with the previous API is that even after copy elision, the initalization value passed as a parameter would always be a copy. With the new API, once copy elision is done, initialization functions can directly initialize allocated memory in place. Related: * #1872 * #1873 --- src-self-hosted/compilation.zig | 72 +++--- src-self-hosted/errmsg.zig | 20 +- src-self-hosted/ir.zig | 15 +- src-self-hosted/main.zig | 5 +- src-self-hosted/package.zig | 6 +- src-self-hosted/scope.zig | 18 +- src-self-hosted/type.zig | 17 +- src-self-hosted/value.zig | 35 +-- std/atomic/queue.zig | 5 +- std/atomic/stack.zig | 5 +- std/build.zig | 56 +++-- std/debug/index.zig | 7 +- std/event/channel.zig | 5 +- std/event/fs.zig | 8 +- std/event/group.zig | 5 +- std/heap.zig | 3 +- std/io.zig | 5 +- std/linked_list.zig | 2 +- std/mem.zig | 13 +- std/os/child_process.zig | 5 +- std/os/index.zig | 5 +- std/zig/parse.zig | 376 +++++++++++++++++++------------- test/tests.zig | 75 ++++--- 23 files changed, 451 insertions(+), 312 deletions(-) diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index c00c7c1d41..d60892432e 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -83,10 +83,11 @@ pub const ZigCompiler = struct { const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; errdefer c.LLVMContextDispose(context_ref); - const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{ + const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node); + node.* = std.atomic.Stack(llvm.ContextRef).Node{ .next = undefined, .data = context_ref, - }); + }; errdefer self.loop.allocator.destroy(node); return LlvmHandle{ .node = node }; @@ -596,7 +597,8 @@ pub const Compilation = struct { } fn initTypes(comp: *Compilation) !void { - comp.meta_type = try comp.arena().create(Type.MetaType{ + comp.meta_type = try comp.arena().create(Type.MetaType); + comp.meta_type.* = Type.MetaType{ .base = Type{ .name = "type", .base = Value{ @@ -608,12 +610,13 @@ pub const Compilation = struct { .abi_alignment = Type.AbiAlignment.init(comp.loop), }, .value = undefined, - }); + }; comp.meta_type.value = &comp.meta_type.base; comp.meta_type.base.base.typ = &comp.meta_type.base; assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null); - comp.void_type = try comp.arena().create(Type.Void{ + comp.void_type = try comp.arena().create(Type.Void); + comp.void_type.* = Type.Void{ .base = Type{ .name = "void", .base = Value{ @@ -624,10 +627,11 @@ pub const Compilation = struct { .id = builtin.TypeId.Void, .abi_alignment = Type.AbiAlignment.init(comp.loop), }, - }); + }; assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null); - comp.noreturn_type = try comp.arena().create(Type.NoReturn{ + comp.noreturn_type = try comp.arena().create(Type.NoReturn); + comp.noreturn_type.* = Type.NoReturn{ .base = Type{ .name = "noreturn", .base = Value{ @@ -638,10 +642,11 @@ pub const Compilation = struct { .id = builtin.TypeId.NoReturn, .abi_alignment = Type.AbiAlignment.init(comp.loop), }, - }); + }; assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null); - comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{ + comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt); + comp.comptime_int_type.* = Type.ComptimeInt{ .base = Type{ .name = "comptime_int", .base = Value{ @@ -652,10 +657,11 @@ pub const Compilation = struct { .id = builtin.TypeId.ComptimeInt, .abi_alignment = Type.AbiAlignment.init(comp.loop), }, - }); + }; assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null); - comp.bool_type = try comp.arena().create(Type.Bool{ + comp.bool_type = try comp.arena().create(Type.Bool); + comp.bool_type.* = Type.Bool{ .base = Type{ .name = "bool", .base = Value{ @@ -666,45 +672,50 @@ pub const Compilation = struct { .id = builtin.TypeId.Bool, .abi_alignment = Type.AbiAlignment.init(comp.loop), }, - }); + }; assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null); - comp.void_value = try comp.arena().create(Value.Void{ + comp.void_value = try comp.arena().create(Value.Void); + comp.void_value.* = Value.Void{ .base = Value{ .id = Value.Id.Void, .typ = &Type.Void.get(comp).base, .ref_count = std.atomic.Int(usize).init(1), }, - }); + }; - comp.true_value = try comp.arena().create(Value.Bool{ + comp.true_value = try comp.arena().create(Value.Bool); + comp.true_value.* = Value.Bool{ .base = Value{ .id = Value.Id.Bool, .typ = &Type.Bool.get(comp).base, .ref_count = std.atomic.Int(usize).init(1), }, .x = true, - }); + }; - comp.false_value = try comp.arena().create(Value.Bool{ + comp.false_value = try comp.arena().create(Value.Bool); + comp.false_value.* = Value.Bool{ .base = Value{ .id = Value.Id.Bool, .typ = &Type.Bool.get(comp).base, .ref_count = std.atomic.Int(usize).init(1), }, .x = false, - }); + }; - comp.noreturn_value = try comp.arena().create(Value.NoReturn{ + comp.noreturn_value = try comp.arena().create(Value.NoReturn); + comp.noreturn_value.* = Value.NoReturn{ .base = Value{ .id = Value.Id.NoReturn, .typ = &Type.NoReturn.get(comp).base, .ref_count = std.atomic.Int(usize).init(1), }, - }); + }; for (CInt.list) |cint, i| { - const c_int_type = try comp.arena().create(Type.Int{ + const c_int_type = try comp.arena().create(Type.Int); + c_int_type.* = Type.Int{ .base = Type{ .name = cint.zig_name, .base = Value{ @@ -720,11 +731,12 @@ pub const Compilation = struct { .bit_count = comp.target.cIntTypeSizeInBits(cint.id), }, .garbage_node = undefined, - }); + }; comp.c_int_types[i] = c_int_type; assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null); } - comp.u8_type = try comp.arena().create(Type.Int{ + comp.u8_type = try comp.arena().create(Type.Int); + comp.u8_type.* = Type.Int{ .base = Type{ .name = "u8", .base = Value{ @@ -740,7 +752,7 @@ pub const Compilation = struct { .bit_count = 8, }, .garbage_node = undefined, - }); + }; assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null); } @@ -829,7 +841,7 @@ pub const Compilation = struct { }; errdefer self.gpa().free(source_code); - const tree = try self.gpa().createOne(ast.Tree); + const tree = try self.gpa().create(ast.Tree); tree.* = try std.zig.parse(self.gpa(), source_code); errdefer { tree.deinit(); @@ -925,7 +937,8 @@ pub const Compilation = struct { } } else { // add new decl - const fn_decl = try self.gpa().create(Decl.Fn{ + const fn_decl = try self.gpa().create(Decl.Fn); + fn_decl.* = Decl.Fn{ .base = Decl{ .id = Decl.Id.Fn, .name = name, @@ -936,7 +949,7 @@ pub const Compilation = struct { }, .value = Decl.Fn.Val{ .Unresolved = {} }, .fn_proto = fn_proto, - }); + }; tree_scope.base.ref(); errdefer self.gpa().destroy(fn_decl); @@ -1140,12 +1153,13 @@ pub const Compilation = struct { } } - const link_lib = try self.gpa().create(LinkLib{ + const link_lib = try self.gpa().create(LinkLib); + link_lib.* = LinkLib{ .name = name, .path = null, .provided_explicitly = provided_explicitly, .symbols = ArrayList([]u8).init(self.gpa()), - }); + }; try self.link_libs_list.append(link_lib); if (is_libc) { self.libc_link_lib = link_lib; diff --git a/src-self-hosted/errmsg.zig b/src-self-hosted/errmsg.zig index 0e552fde7e..fc49fad410 100644 --- a/src-self-hosted/errmsg.zig +++ b/src-self-hosted/errmsg.zig @@ -118,7 +118,8 @@ pub const Msg = struct { const realpath = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); errdefer comp.gpa().free(realpath); - const msg = try comp.gpa().create(Msg{ + const msg = try comp.gpa().create(Msg); + msg.* = Msg{ .text = text, .realpath = realpath, .data = Data{ @@ -128,7 +129,7 @@ pub const Msg = struct { .span = span, }, }, - }); + }; tree_scope.base.ref(); return msg; } @@ -139,13 +140,14 @@ pub const Msg = struct { const realpath_copy = try mem.dupe(comp.gpa(), u8, realpath); errdefer comp.gpa().free(realpath_copy); - const msg = try comp.gpa().create(Msg{ + const msg = try comp.gpa().create(Msg); + msg.* = Msg{ .text = text, .realpath = realpath_copy, .data = Data{ .Cli = Cli{ .allocator = comp.gpa() }, }, - }); + }; return msg; } @@ -164,7 +166,8 @@ pub const Msg = struct { var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; try parse_error.render(&tree_scope.tree.tokens, out_stream); - const msg = try comp.gpa().create(Msg{ + const msg = try comp.gpa().create(Msg); + msg.* = Msg{ .text = undefined, .realpath = realpath_copy, .data = Data{ @@ -177,7 +180,7 @@ pub const Msg = struct { }, }, }, - }); + }; tree_scope.base.ref(); msg.text = text_buf.toOwnedSlice(); return msg; @@ -203,7 +206,8 @@ pub const Msg = struct { var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; try parse_error.render(&tree.tokens, out_stream); - const msg = try allocator.create(Msg{ + const msg = try allocator.create(Msg); + msg.* = Msg{ .text = undefined, .realpath = realpath_copy, .data = Data{ @@ -216,7 +220,7 @@ pub const Msg = struct { }, }, }, - }); + }; msg.text = text_buf.toOwnedSlice(); errdefer allocator.destroy(msg); diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 562765b354..0362bb4ef8 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1021,12 +1021,13 @@ pub const Builder = struct { pub const Error = Analyze.Error; pub fn init(comp: *Compilation, tree_scope: *Scope.AstTree, begin_scope: ?*Scope) !Builder { - const code = try comp.gpa().create(Code{ + const code = try comp.gpa().create(Code); + code.* = Code{ .basic_block_list = undefined, .arena = std.heap.ArenaAllocator.init(comp.gpa()), .return_type = null, .tree_scope = tree_scope, - }); + }; code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); errdefer code.destroy(comp.gpa()); @@ -1052,7 +1053,8 @@ pub const Builder = struct { /// No need to clean up resources thanks to the arena allocator. pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { - const basic_block = try self.arena().create(BasicBlock{ + const basic_block = try self.arena().create(BasicBlock); + basic_block.* = BasicBlock{ .ref_count = 0, .name_hint = name_hint, .debug_id = self.next_debug_id, @@ -1063,7 +1065,7 @@ pub const Builder = struct { .ref_instruction = null, .llvm_block = undefined, .llvm_exit_block = undefined, - }); + }; self.next_debug_id += 1; return basic_block; } @@ -1774,7 +1776,8 @@ pub const Builder = struct { params: I.Params, is_generated: bool, ) !*Inst { - const inst = try self.arena().create(I{ + const inst = try self.arena().create(I); + inst.* = I{ .base = Inst{ .id = Inst.typeToId(I), .is_generated = is_generated, @@ -1793,7 +1796,7 @@ pub const Builder = struct { .owner_bb = self.current_basic_block, }, .params = params, - }); + }; // Look at the params and ref() other instructions comptime var i = 0; diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 0742cbfe65..1403ab860d 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -944,12 +944,13 @@ const CliPkg = struct { parent: ?*CliPkg, pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg { - var pkg = try allocator.create(CliPkg{ + var pkg = try allocator.create(CliPkg); + pkg.* = CliPkg{ .name = name, .path = path, .children = ArrayList(*CliPkg).init(allocator), .parent = parent, - }); + }; return pkg; } diff --git a/src-self-hosted/package.zig b/src-self-hosted/package.zig index 720b279651..0d31731b55 100644 --- a/src-self-hosted/package.zig +++ b/src-self-hosted/package.zig @@ -15,11 +15,13 @@ pub const Package = struct { /// makes internal copies of root_src_dir and root_src_path /// allocator should be an arena allocator because Package never frees anything pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package { - return allocator.create(Package{ + const ptr = try allocator.create(Package); + ptr.* = Package{ .root_src_dir = try Buffer.init(allocator, root_src_dir), .root_src_path = try Buffer.init(allocator, root_src_path), .table = Table.init(allocator), - }); + }; + return ptr; } pub fn add(self: *Package, name: []const u8, package: *Package) !void { diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig index 43d3b5a784..b14c073a9e 100644 --- a/src-self-hosted/scope.zig +++ b/src-self-hosted/scope.zig @@ -120,7 +120,7 @@ pub const Scope = struct { /// Creates a Root scope with 1 reference /// Takes ownership of realpath pub fn create(comp: *Compilation, realpath: []u8) !*Root { - const self = try comp.gpa().createOne(Root); + const self = try comp.gpa().create(Root); self.* = Root{ .base = Scope{ .id = Id.Root, @@ -150,7 +150,7 @@ pub const Scope = struct { /// Creates a scope with 1 reference /// Takes ownership of tree, will deinit and destroy when done. pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree { - const self = try comp.gpa().createOne(AstTree); + const self = try comp.gpa().create(AstTree); self.* = AstTree{ .base = undefined, .tree = tree, @@ -182,7 +182,7 @@ pub const Scope = struct { /// Creates a Decls scope with 1 reference pub fn create(comp: *Compilation, parent: *Scope) !*Decls { - const self = try comp.gpa().createOne(Decls); + const self = try comp.gpa().create(Decls); self.* = Decls{ .base = undefined, .table = event.RwLocked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())), @@ -235,7 +235,7 @@ pub const Scope = struct { /// Creates a Block scope with 1 reference pub fn create(comp: *Compilation, parent: *Scope) !*Block { - const self = try comp.gpa().createOne(Block); + const self = try comp.gpa().create(Block); self.* = Block{ .base = undefined, .incoming_values = undefined, @@ -262,7 +262,7 @@ pub const Scope = struct { /// Creates a FnDef scope with 1 reference /// Must set the fn_val later pub fn create(comp: *Compilation, parent: *Scope) !*FnDef { - const self = try comp.gpa().createOne(FnDef); + const self = try comp.gpa().create(FnDef); self.* = FnDef{ .base = undefined, .fn_val = null, @@ -281,7 +281,7 @@ pub const Scope = struct { /// Creates a CompTime scope with 1 reference pub fn create(comp: *Compilation, parent: *Scope) !*CompTime { - const self = try comp.gpa().createOne(CompTime); + const self = try comp.gpa().create(CompTime); self.* = CompTime{ .base = undefined }; self.base.init(Id.CompTime, parent); return self; @@ -309,7 +309,7 @@ pub const Scope = struct { kind: Kind, defer_expr_scope: *DeferExpr, ) !*Defer { - const self = try comp.gpa().createOne(Defer); + const self = try comp.gpa().create(Defer); self.* = Defer{ .base = undefined, .defer_expr_scope = defer_expr_scope, @@ -333,7 +333,7 @@ pub const Scope = struct { /// Creates a DeferExpr scope with 1 reference pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr { - const self = try comp.gpa().createOne(DeferExpr); + const self = try comp.gpa().create(DeferExpr); self.* = DeferExpr{ .base = undefined, .expr_node = expr_node, @@ -398,7 +398,7 @@ pub const Scope = struct { } fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var { - const self = try comp.gpa().createOne(Var); + const self = try comp.gpa().create(Var); self.* = Var{ .base = undefined, .name = name, diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index fa31343902..8a05594b30 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -413,7 +413,7 @@ pub const Type = struct { key.ref(); errdefer key.deref(comp); - const self = try comp.gpa().createOne(Fn); + const self = try comp.gpa().create(Fn); self.* = Fn{ .base = undefined, .key = key, @@ -615,11 +615,12 @@ pub const Type = struct { } } - const self = try comp.gpa().create(Int{ + const self = try comp.gpa().create(Int); + self.* = Int{ .base = undefined, .key = key, .garbage_node = undefined, - }); + }; errdefer comp.gpa().destroy(self); const u_or_i = "ui"[@boolToInt(key.is_signed)]; @@ -781,11 +782,12 @@ pub const Type = struct { } } - const self = try comp.gpa().create(Pointer{ + const self = try comp.gpa().create(Pointer); + self.* = Pointer{ .base = undefined, .key = normal_key, .garbage_node = undefined, - }); + }; errdefer comp.gpa().destroy(self); const size_str = switch (self.key.size) { @@ -879,11 +881,12 @@ pub const Type = struct { } } - const self = try comp.gpa().create(Array{ + const self = try comp.gpa().create(Array); + self.* = Array{ .base = undefined, .key = key, .garbage_node = undefined, - }); + }; errdefer comp.gpa().destroy(self); const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name); diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index e6dca4eff7..9431c614b9 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -135,14 +135,15 @@ pub const Value = struct { symbol_name: Buffer, pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto { - const self = try comp.gpa().create(FnProto{ + const self = try comp.gpa().create(FnProto); + self.* = FnProto{ .base = Value{ .id = Value.Id.FnProto, .typ = &fn_type.base, .ref_count = std.atomic.Int(usize).init(1), }, .symbol_name = symbol_name, - }); + }; fn_type.base.base.ref(); return self; } @@ -190,14 +191,16 @@ pub const Value = struct { /// Creates a Fn value with 1 ref /// Takes ownership of symbol_name pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn { - const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{ + const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node); + link_set_node.* = Compilation.FnLinkSet.Node{ .data = null, .next = undefined, .prev = undefined, - }); + }; errdefer comp.gpa().destroy(link_set_node); - const self = try comp.gpa().create(Fn{ + const self = try comp.gpa().create(Fn); + self.* = Fn{ .base = Value{ .id = Value.Id.Fn, .typ = &fn_type.base, @@ -209,7 +212,7 @@ pub const Value = struct { .symbol_name = symbol_name, .containing_object = Buffer.initNull(comp.gpa()), .link_set_node = link_set_node, - }); + }; fn_type.base.base.ref(); fndef_scope.fn_val = self; fndef_scope.base.ref(); @@ -353,7 +356,8 @@ pub const Value = struct { var ptr_type_consumed = false; errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); - const self = try comp.gpa().create(Value.Ptr{ + const self = try comp.gpa().create(Value.Ptr); + self.* = Value.Ptr{ .base = Value{ .id = Value.Id.Ptr, .typ = &ptr_type.base, @@ -366,7 +370,7 @@ pub const Value = struct { }, }, .mut = Mut.CompTimeConst, - }); + }; ptr_type_consumed = true; errdefer comp.gpa().destroy(self); @@ -430,14 +434,15 @@ pub const Value = struct { }) catch unreachable); errdefer array_type.base.base.deref(comp); - const self = try comp.gpa().create(Value.Array{ + const self = try comp.gpa().create(Value.Array); + self.* = Value.Array{ .base = Value{ .id = Value.Id.Array, .typ = &array_type.base, .ref_count = std.atomic.Int(usize).init(1), }, .special = Special{ .OwnedBuffer = buffer }, - }); + }; errdefer comp.gpa().destroy(self); return self; @@ -509,14 +514,15 @@ pub const Value = struct { big_int: std.math.big.Int, pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int { - const self = try comp.gpa().create(Value.Int{ + const self = try comp.gpa().create(Value.Int); + self.* = Value.Int{ .base = Value{ .id = Value.Id.Int, .typ = typ, .ref_count = std.atomic.Int(usize).init(1), }, .big_int = undefined, - }); + }; typ.base.ref(); errdefer comp.gpa().destroy(self); @@ -557,14 +563,15 @@ pub const Value = struct { old.base.typ.base.ref(); errdefer old.base.typ.base.deref(comp); - const new = try comp.gpa().create(Value.Int{ + const new = try comp.gpa().create(Value.Int); + new.* = Value.Int{ .base = Value{ .id = Value.Id.Int, .typ = old.base.typ, .ref_count = std.atomic.Int(usize).init(1), }, .big_int = undefined, - }); + }; errdefer comp.gpa().destroy(new); new.big_int = try old.big_int.clone(); diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 6c61bcc048..183c434dc5 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -221,11 +221,12 @@ fn startPuts(ctx: *Context) u8 { while (put_count != 0) : (put_count -= 1) { std.os.time.sleep(1); // let the os scheduler be our fuzz const x = @bitCast(i32, r.random.scalar(u32)); - const node = ctx.allocator.create(Queue(i32).Node{ + const node = ctx.allocator.create(Queue(i32).Node) catch unreachable; + node.* = Queue(i32).Node{ .prev = undefined, .next = undefined, .data = x, - }) catch unreachable; + }; ctx.queue.put(node); _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); } diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 1e4981353b..503fa0c0ce 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -155,10 +155,11 @@ fn startPuts(ctx: *Context) u8 { while (put_count != 0) : (put_count -= 1) { std.os.time.sleep(1); // let the os scheduler be our fuzz const x = @bitCast(i32, r.random.scalar(u32)); - const node = ctx.allocator.create(Stack(i32).Node{ + const node = ctx.allocator.create(Stack(i32).Node) catch unreachable; + node.* = Stack(i32).Node{ .next = undefined, .data = x, - }) catch unreachable; + }; ctx.stack.push(node); _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst); } diff --git a/std/build.zig b/std/build.zig index 90f5bec656..6f58594190 100644 --- a/std/build.zig +++ b/std/build.zig @@ -89,7 +89,7 @@ pub const Builder = struct { }; pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder { - const env_map = allocator.createOne(BufMap) catch unreachable; + const env_map = allocator.create(BufMap) catch unreachable; env_map.* = os.getEnvMap(allocator) catch unreachable; var self = Builder{ .zig_exe = zig_exe, @@ -170,7 +170,8 @@ pub const Builder = struct { } pub fn addTest(self: *Builder, root_src: []const u8) *TestStep { - const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable; + const test_step = self.allocator.create(TestStep) catch unreachable; + test_step.* = TestStep.init(self, root_src); return test_step; } @@ -202,18 +203,21 @@ pub const Builder = struct { } pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep { - const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable; + const write_file_step = self.allocator.create(WriteFileStep) catch unreachable; + write_file_step.* = WriteFileStep.init(self, file_path, data); return write_file_step; } pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep { const data = self.fmt(format, args); - const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable; + const log_step = self.allocator.create(LogStep) catch unreachable; + log_step.* = LogStep.init(self, data); return log_step; } pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep { - const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable; + const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable; + remove_dir_step.* = RemoveDirStep.init(self, dir_path); return remove_dir_step; } @@ -414,10 +418,11 @@ pub const Builder = struct { } pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { - const step_info = self.allocator.create(TopLevelStep{ + const step_info = self.allocator.create(TopLevelStep) catch unreachable; + step_info.* = TopLevelStep{ .step = Step.initNoOp(name, self.allocator), .description = description, - }) catch unreachable; + }; self.top_level_steps.append(step_info) catch unreachable; return &step_info.step; } @@ -616,7 +621,8 @@ pub const Builder = struct { const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable; self.pushInstalledFile(full_dest_path); - const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable; + const install_step = self.allocator.create(InstallFileStep) catch unreachable; + install_step.* = InstallFileStep.init(self, src_path, full_dest_path); return install_step; } @@ -865,43 +871,51 @@ pub const LibExeObjStep = struct { }; pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver); return self; } pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep { - const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initC(builder, name, Kind.Lib, version, false); return self; } pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0)); return self; } pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep { - const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true); return self; } pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); return self; } pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { - const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false); self.object_src = src; return self; } pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0)); return self; } pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep { - const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable; + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false); return self; } @@ -1914,13 +1928,14 @@ pub const CommandStep = struct { /// ::argv is copied. pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep { - const self = builder.allocator.create(CommandStep{ + const self = builder.allocator.create(CommandStep) catch unreachable; + self.* = CommandStep{ .builder = builder, .step = Step.init(argv[0], builder.allocator, make), .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable, .cwd = cwd, .env_map = env_map, - }) catch unreachable; + }; mem.copy([]const u8, self.argv, argv); self.step.name = self.argv[0]; @@ -1949,12 +1964,13 @@ const InstallArtifactStep = struct { LibExeObjStep.Kind.Exe => builder.exe_dir, LibExeObjStep.Kind.Lib => builder.lib_dir, }; - const self = builder.allocator.create(Self{ + const self = builder.allocator.create(Self) catch unreachable; + self.* = Self{ .builder = builder, .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), .artifact = artifact, .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, - }) catch unreachable; + }; self.step.dependOn(&artifact.step); builder.pushInstalledFile(self.dest_file); if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { diff --git a/std/debug/index.zig b/std/debug/index.zig index 445f943594..838bd0c166 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -751,7 +751,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { const self_file = try os.openSelfExe(); defer self_file.close(); - const coff_obj = try allocator.createOne(coff.Coff); + const coff_obj = try allocator.create(coff.Coff); coff_obj.* = coff.Coff{ .in_file = self_file, .allocator = allocator, @@ -1036,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { } } } - const sentinel = try allocator.createOne(macho.nlist_64); + const sentinel = try allocator.create(macho.nlist_64); sentinel.* = macho.nlist_64{ .n_strx = 0, .n_type = 36, @@ -1949,7 +1949,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { try di.dwarf_seekable_stream.seekTo(compile_unit_pos); - const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64)); + 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; diff --git a/std/event/channel.zig b/std/event/channel.zig index f04ad1604e..f8cdae6208 100644 --- a/std/event/channel.zig +++ b/std/event/channel.zig @@ -54,7 +54,8 @@ pub fn Channel(comptime T: type) type { const buffer_nodes = try loop.allocator.alloc(T, capacity); errdefer loop.allocator.free(buffer_nodes); - const self = try loop.allocator.create(SelfChannel{ + const self = try loop.allocator.create(SelfChannel); + self.* = SelfChannel{ .loop = loop, .buffer_len = 0, .buffer_nodes = buffer_nodes, @@ -66,7 +67,7 @@ pub fn Channel(comptime T: type) type { .or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(), .get_count = 0, .put_count = 0, - }); + }; errdefer loop.allocator.destroy(self); return self; diff --git a/std/event/fs.zig b/std/event/fs.zig index 7e77b3e6e2..097f2beddc 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -495,7 +495,7 @@ pub const CloseOperation = struct { }; pub fn start(loop: *Loop) (error{OutOfMemory}!*CloseOperation) { - const self = try loop.allocator.createOne(CloseOperation); + const self = try loop.allocator.create(CloseOperation); self.* = CloseOperation{ .loop = loop, .os_data = switch (builtin.os) { @@ -787,7 +787,7 @@ pub fn Watch(comptime V: type) type { }, builtin.Os.windows => { - const self = try loop.allocator.createOne(Self); + const self = try loop.allocator.create(Self); errdefer loop.allocator.destroy(self); self.* = Self{ .channel = channel, @@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type { }, builtin.Os.macosx, builtin.Os.freebsd => { - const self = try loop.allocator.createOne(Self); + const self = try loop.allocator.create(Self); errdefer loop.allocator.destroy(self); self.* = Self{ @@ -1068,7 +1068,7 @@ pub fn Watch(comptime V: type) type { } } else { errdefer _ = self.os_data.dir_table.remove(dirname); - const dir = try self.channel.loop.allocator.createOne(OsData.Dir); + const dir = try self.channel.loop.allocator.create(OsData.Dir); errdefer self.channel.loop.allocator.destroy(dir); dir.* = OsData.Dir{ diff --git a/std/event/group.zig b/std/event/group.zig index 0e9c2d9655..7f6b5d953b 100644 --- a/std/event/group.zig +++ b/std/event/group.zig @@ -42,10 +42,11 @@ pub fn Group(comptime ReturnType: type) type { /// Add a promise to the group. Thread-safe. pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) { - const node = try self.lock.loop.allocator.create(Stack.Node{ + const node = try self.lock.loop.allocator.create(Stack.Node); + node.* = Stack.Node{ .next = undefined, .data = handle, - }); + }; self.alloc_stack.push(node); } diff --git a/std/heap.zig b/std/heap.zig index 46b247fa7e..fd2ce1e965 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -518,7 +518,8 @@ fn testAllocator(allocator: *mem.Allocator) !void { var slice = try allocator.alloc(*i32, 100); assert(slice.len == 100); for (slice) |*item, i| { - item.* = try allocator.create(@intCast(i32, i)); + item.* = try allocator.create(i32); + item.*.* = @intCast(i32, i); } slice = try allocator.realloc(*i32, slice, 20000); diff --git a/std/io.zig b/std/io.zig index 46625cd34b..c8701aeda6 100644 --- a/std/io.zig +++ b/std/io.zig @@ -944,12 +944,13 @@ pub const BufferedAtomicFile = struct { pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile { // TODO with well defined copy elision we don't need this allocation - var self = try allocator.create(BufferedAtomicFile{ + var self = try allocator.create(BufferedAtomicFile); + self.* = BufferedAtomicFile{ .atomic_file = undefined, .file_stream = undefined, .buffered_stream = undefined, .allocator = allocator, - }); + }; errdefer allocator.destroy(self); self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode); diff --git a/std/linked_list.zig b/std/linked_list.zig index c3db55b5a6..7021cac707 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -190,7 +190,7 @@ pub fn LinkedList(comptime T: type) type { /// Returns: /// A pointer to the new node. pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { - return allocator.create(Node(undefined)); + return allocator.create(Node); } /// Deallocate a node. diff --git a/std/mem.zig b/std/mem.zig index fb5f6fd5da..a403d80453 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -36,20 +36,9 @@ pub const Allocator = struct { /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` freeFn: fn (self: *Allocator, old_mem: []u8) void, - /// Call `destroy` with the result - /// TODO this is deprecated. use createOne instead - pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { - const T = @typeOf(init); - if (@sizeOf(T) == 0) return &(T{}); - const slice = try self.alloc(T, 1); - const ptr = &slice[0]; - ptr.* = init; - return ptr; - } - /// Call `destroy` with the result. /// Returns undefined memory. - pub fn createOne(self: *Allocator, comptime T: type) Error!*T { + pub fn create(self: *Allocator, comptime T: type) Error!*T { if (@sizeOf(T) == 0) return &(T{}); const slice = try self.alloc(T, 1); return &slice[0]; diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 0aa896ff1b..9f33bee905 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -88,7 +88,8 @@ pub const ChildProcess = struct { /// First argument in argv is the executable. /// On success must call deinit. pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess { - const child = try allocator.create(ChildProcess{ + const child = try allocator.create(ChildProcess); + child.* = ChildProcess{ .allocator = allocator, .argv = argv, .pid = undefined, @@ -109,7 +110,7 @@ pub const ChildProcess = struct { .stdin_behavior = StdIo.Inherit, .stdout_behavior = StdIo.Inherit, .stderr_behavior = StdIo.Inherit, - }); + }; errdefer allocator.destroy(child); return child; } diff --git a/std/os/index.zig b/std/os/index.zig index 75abe3bbde..0d0e07bfa3 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -3047,7 +3047,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread 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{ + 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, @@ -3056,7 +3057,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread }, }, .inner = context, - }) catch unreachable; + }; 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 { diff --git a/std/zig/parse.zig b/std/zig/parse.zig index a216484d7d..783464c620 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -17,14 +17,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { defer stack.deinit(); const arena = &tree_arena.allocator; - const root_node = try arena.create(ast.Node.Root{ + const root_node = try arena.create(ast.Node.Root); + root_node.* = ast.Node.Root{ .base = ast.Node{ .id = ast.Node.Id.Root }, .decls = ast.Node.Root.DeclList.init(arena), .doc_comments = null, .shebang = null, // initialized when we get the eof token .eof_token = undefined, - }); + }; var tree = ast.Tree{ .source = source, @@ -75,20 +76,22 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { Token.Id.Keyword_test => { stack.append(State.TopLevel) catch unreachable; - const block = try arena.create(ast.Node.Block{ + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = null, .lbrace = undefined, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); - const test_node = try arena.create(ast.Node.TestDecl{ + }; + const test_node = try arena.create(ast.Node.TestDecl); + test_node.* = ast.Node.TestDecl{ .base = ast.Node{ .id = ast.Node.Id.TestDecl }, .doc_comments = comments, .test_token = token_index, .name = undefined, .body_node = &block.base, - }); + }; try root_node.decls.push(&test_node.base); try stack.append(State{ .Block = block }); try stack.append(State{ @@ -119,19 +122,21 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_comptime => { - const block = try arena.create(ast.Node.Block{ + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = null, .lbrace = undefined, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); - const node = try arena.create(ast.Node.Comptime{ + }; + const node = try arena.create(ast.Node.Comptime); + node.* = ast.Node.Comptime{ .base = ast.Node{ .id = ast.Node.Id.Comptime }, .comptime_token = token_index, .expr = &block.base, .doc_comments = comments, - }); + }; try root_node.decls.push(&node.base); stack.append(State.TopLevel) catch unreachable; @@ -235,14 +240,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - const node = try arena.create(ast.Node.Use{ + const node = try arena.create(ast.Node.Use); + node.* = ast.Node.Use{ .base = ast.Node{ .id = ast.Node.Id.Use }, .use_token = token_index, .visib_token = ctx.visib_token, .expr = undefined, .semicolon_token = undefined, .doc_comments = ctx.comments, - }); + }; try ctx.decls.push(&node.base); stack.append(State{ @@ -276,7 +282,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => { - const fn_proto = try arena.create(ast.Node.FnProto{ + const fn_proto = try arena.create(ast.Node.FnProto); + fn_proto.* = ast.Node.FnProto{ .base = ast.Node{ .id = ast.Node.Id.FnProto }, .doc_comments = ctx.comments, .visib_token = ctx.visib_token, @@ -292,7 +299,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .lib_name = ctx.lib_name, .align_expr = null, .section_expr = null, - }); + }; try ctx.decls.push(&fn_proto.base); stack.append(State{ .FnDef = fn_proto }) catch unreachable; try stack.append(State{ .FnProto = fn_proto }); @@ -309,12 +316,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_async => { - const async_node = try arena.create(ast.Node.AsyncAttribute{ + const async_node = try arena.create(ast.Node.AsyncAttribute); + async_node.* = ast.Node.AsyncAttribute{ .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, .async_token = token_index, .allocator_type = null, .rangle_bracket = null, - }); + }; fn_proto.async_attr = async_node; try stack.append(State{ @@ -341,13 +349,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.TopLevelExternOrField => |ctx| { if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| { - const node = try arena.create(ast.Node.StructField{ + const node = try arena.create(ast.Node.StructField); + node.* = ast.Node.StructField{ .base = ast.Node{ .id = ast.Node.Id.StructField }, .doc_comments = ctx.comments, .visib_token = ctx.visib_token, .name_token = identifier, .type_expr = undefined, - }); + }; const node_ptr = try ctx.container_decl.fields_and_decls.addOne(); node_ptr.* = &node.base; @@ -391,7 +400,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token = nextToken(&tok_it, &tree); const token_index = token.index; const token_ptr = token.ptr; - const node = try arena.create(ast.Node.ContainerDecl{ + const node = try arena.create(ast.Node.ContainerDecl); + node.* = ast.Node.ContainerDecl{ .base = ast.Node{ .id = ast.Node.Id.ContainerDecl }, .layout_token = ctx.layout_token, .kind_token = switch (token_ptr.id) { @@ -405,7 +415,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena), .lbrace_token = undefined, .rbrace_token = undefined, - }); + }; ctx.opt_ctx.store(&node.base); stack.append(State{ .ContainerDecl = node }) catch unreachable; @@ -464,13 +474,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { Token.Id.Identifier => { switch (tree.tokens.at(container_decl.kind_token).id) { Token.Id.Keyword_struct => { - const node = try arena.create(ast.Node.StructField{ + const node = try arena.create(ast.Node.StructField); + node.* = ast.Node.StructField{ .base = ast.Node{ .id = ast.Node.Id.StructField }, .doc_comments = comments, .visib_token = null, .name_token = token_index, .type_expr = undefined, - }); + }; const node_ptr = try container_decl.fields_and_decls.addOne(); node_ptr.* = &node.base; @@ -485,13 +496,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_union => { - const node = try arena.create(ast.Node.UnionTag{ + const node = try arena.create(ast.Node.UnionTag); + node.* = ast.Node.UnionTag{ .base = ast.Node{ .id = ast.Node.Id.UnionTag }, .name_token = token_index, .type_expr = null, .value_expr = null, .doc_comments = comments, - }); + }; try container_decl.fields_and_decls.push(&node.base); try stack.append(State{ @@ -506,12 +518,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_enum => { - const node = try arena.create(ast.Node.EnumTag{ + const node = try arena.create(ast.Node.EnumTag); + node.* = ast.Node.EnumTag{ .base = ast.Node{ .id = ast.Node.Id.EnumTag }, .name_token = token_index, .value = null, .doc_comments = comments, - }); + }; try container_decl.fields_and_decls.push(&node.base); try stack.append(State{ @@ -593,7 +606,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.VarDecl => |ctx| { - const var_decl = try arena.create(ast.Node.VarDecl{ + const var_decl = try arena.create(ast.Node.VarDecl); + var_decl.* = ast.Node.VarDecl{ .base = ast.Node{ .id = ast.Node.Id.VarDecl }, .doc_comments = ctx.comments, .visib_token = ctx.visib_token, @@ -609,7 +623,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .name_token = undefined, .eq_token = undefined, .semicolon_token = undefined, - }); + }; try ctx.list.push(&var_decl.base); try stack.append(State{ .VarDeclAlign = var_decl }); @@ -708,13 +722,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.LBrace => { - const block = try arena.create(ast.Node.Block{ + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = null, .lbrace = token_index, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); + }; fn_proto.body_node = &block.base; stack.append(State{ .Block = block }) catch unreachable; continue; @@ -770,10 +785,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { // TODO: this is a special case. Remove this when #760 is fixed if (token_ptr.id == Token.Id.Keyword_anyerror) { if (tok_it.peek().?.id == Token.Id.LBrace) { - const error_type_node = try arena.create(ast.Node.ErrorType{ + const error_type_node = try arena.create(ast.Node.ErrorType); + error_type_node.* = ast.Node.ErrorType{ .base = ast.Node{ .id = ast.Node.Id.ErrorType }, .token = token_index, - }); + }; fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = &error_type_node.base }; continue; } @@ -791,14 +807,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| { continue; } - const param_decl = try arena.create(ast.Node.ParamDecl{ + const param_decl = try arena.create(ast.Node.ParamDecl); + param_decl.* = ast.Node.ParamDecl{ .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, .comptime_token = null, .noalias_token = null, .name_token = null, .type_node = undefined, .var_args_token = null, - }); + }; try fn_proto.params.push(¶m_decl.base); stack.append(State{ @@ -877,13 +894,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.LBrace => { - const block = try arena.create(ast.Node.Block{ + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = ctx.label, .lbrace = token_index, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); + }; ctx.opt_ctx.store(&block.base); stack.append(State{ .Block = block }) catch unreachable; continue; @@ -970,7 +988,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } }, State.While => |ctx| { - const node = try arena.create(ast.Node.While{ + const node = try arena.create(ast.Node.While); + node.* = ast.Node.While{ .base = ast.Node{ .id = ast.Node.Id.While }, .label = ctx.label, .inline_token = ctx.inline_token, @@ -980,7 +999,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .continue_expr = null, .body = undefined, .@"else" = null, - }); + }; ctx.opt_ctx.store(&node.base); stack.append(State{ .Else = &node.@"else" }) catch unreachable; try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); @@ -999,7 +1018,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, State.For => |ctx| { - const node = try arena.create(ast.Node.For{ + const node = try arena.create(ast.Node.For); + node.* = ast.Node.For{ .base = ast.Node{ .id = ast.Node.Id.For }, .label = ctx.label, .inline_token = ctx.inline_token, @@ -1008,7 +1028,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .payload = null, .body = undefined, .@"else" = null, - }); + }; ctx.opt_ctx.store(&node.base); stack.append(State{ .Else = &node.@"else" }) catch unreachable; try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }); @@ -1020,12 +1040,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, State.Else => |dest| { if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| { - const node = try arena.create(ast.Node.Else{ + const node = try arena.create(ast.Node.Else); + node.* = ast.Node.Else{ .base = ast.Node{ .id = ast.Node.Id.Else }, .else_token = else_token, .payload = null, .body = undefined, - }); + }; dest.* = node; stack.append(State{ .Expression = OptionalCtx{ .Required = &node.body } }) catch unreachable; @@ -1083,11 +1104,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => { - const node = try arena.create(ast.Node.Defer{ + const node = try arena.create(ast.Node.Defer); + node.* = ast.Node.Defer{ .base = ast.Node{ .id = ast.Node.Id.Defer }, .defer_token = token_index, .expr = undefined, - }); + }; const node_ptr = try block.statements.addOne(); node_ptr.* = &node.base; @@ -1096,13 +1118,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LBrace => { - const inner_block = try arena.create(ast.Node.Block{ + const inner_block = try arena.create(ast.Node.Block); + inner_block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = null, .lbrace = token_index, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); + }; try block.statements.push(&inner_block.base); stack.append(State{ .Block = inner_block }) catch unreachable; @@ -1164,14 +1187,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.AsmOutput{ + const node = try arena.create(ast.Node.AsmOutput); + node.* = ast.Node.AsmOutput{ .base = ast.Node{ .id = ast.Node.Id.AsmOutput }, .lbracket = lbracket_index, .symbolic_name = undefined, .constraint = undefined, .kind = undefined, .rparen = undefined, - }); + }; try items.push(node); stack.append(State{ .AsmOutputItems = items }) catch unreachable; @@ -1218,14 +1242,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.AsmInput{ + const node = try arena.create(ast.Node.AsmInput); + node.* = ast.Node.AsmInput{ .base = ast.Node{ .id = ast.Node.Id.AsmInput }, .lbracket = lbracket_index, .symbolic_name = undefined, .constraint = undefined, .expr = undefined, .rparen = undefined, - }); + }; try items.push(node); stack.append(State{ .AsmInputItems = items }) catch unreachable; @@ -1283,12 +1308,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.FieldInitializer{ + const node = try arena.create(ast.Node.FieldInitializer); + node.* = ast.Node.FieldInitializer{ .base = ast.Node{ .id = ast.Node.Id.FieldInitializer }, .period_token = undefined, .name_token = undefined, .expr = undefined, - }); + }; try list_state.list.push(&node.base); stack.append(State{ .FieldInitListCommaOrEnd = list_state }) catch unreachable; @@ -1390,13 +1416,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { } const comments = try eatDocComments(arena, &tok_it, &tree); - const node = try arena.create(ast.Node.SwitchCase{ + const node = try arena.create(ast.Node.SwitchCase); + node.* = ast.Node.SwitchCase{ .base = ast.Node{ .id = ast.Node.Id.SwitchCase }, .items = ast.Node.SwitchCase.ItemList.init(arena), .payload = null, .expr = undefined, .arrow_token = undefined, - }); + }; try list_state.list.push(&node.base); try stack.append(State{ .SwitchCaseCommaOrEnd = list_state }); try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } }); @@ -1427,10 +1454,11 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (token_ptr.id == Token.Id.Keyword_else) { - const else_node = try arena.create(ast.Node.SwitchElse{ + const else_node = try arena.create(ast.Node.SwitchElse); + else_node.* = ast.Node.SwitchElse{ .base = ast.Node{ .id = ast.Node.Id.SwitchElse }, .token = token_index, - }); + }; try switch_case.items.push(&else_node.base); try stack.append(State{ @@ -1537,7 +1565,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.ExternType => |ctx| { if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| { - const fn_proto = try arena.create(ast.Node.FnProto{ + const fn_proto = try arena.create(ast.Node.FnProto); + fn_proto.* = ast.Node.FnProto{ .base = ast.Node{ .id = ast.Node.Id.FnProto }, .doc_comments = ctx.comments, .visib_token = null, @@ -1553,7 +1582,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .lib_name = null, .align_expr = null, .section_expr = null, - }); + }; ctx.opt_ctx.store(&fn_proto.base); stack.append(State{ .FnProto = fn_proto }) catch unreachable; continue; @@ -1711,12 +1740,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.Payload{ + const node = try arena.create(ast.Node.Payload); + node.* = ast.Node.Payload{ .base = ast.Node{ .id = ast.Node.Id.Payload }, .lpipe = token_index, .error_symbol = undefined, .rpipe = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ @@ -1747,13 +1777,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.PointerPayload{ + const node = try arena.create(ast.Node.PointerPayload); + node.* = ast.Node.PointerPayload{ .base = ast.Node{ .id = ast.Node.Id.PointerPayload }, .lpipe = token_index, .ptr_token = null, .value_symbol = undefined, .rpipe = undefined, - }); + }; opt_ctx.store(&node.base); try stack.append(State{ @@ -1790,14 +1821,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.PointerIndexPayload{ + const node = try arena.create(ast.Node.PointerIndexPayload); + node.* = ast.Node.PointerIndexPayload{ .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload }, .lpipe = token_index, .ptr_token = null, .value_symbol = undefined, .index_symbol = null, .rpipe = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ @@ -1824,12 +1856,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => { - const node = try arena.create(ast.Node.ControlFlowExpression{ + const node = try arena.create(ast.Node.ControlFlowExpression); + node.* = ast.Node.ControlFlowExpression{ .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression }, .ltoken = token_index, .kind = undefined, .rhs = null, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .Expression = OptionalCtx{ .Optional = &node.rhs } }) catch unreachable; @@ -1853,7 +1886,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => { - const node = try arena.create(ast.Node.PrefixOp{ + const node = try arena.create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, .op_token = token_index, .op = switch (token_ptr.id) { @@ -1863,7 +1897,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { else => unreachable, }, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; @@ -1887,13 +1921,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = ellipsis3, .op = ast.Node.InfixOp.Op.Range, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; continue; @@ -1912,13 +1947,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAssignment(token_ptr.id)) |ass_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = ass_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .AssignmentExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } }); @@ -1942,13 +1978,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = unwrap_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .UnwrapExpressionEnd = opt_ctx.toRequired() }) catch unreachable; @@ -1974,13 +2011,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = or_token, .op = ast.Node.InfixOp.Op.BoolOr, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BoolOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .BoolAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -1998,13 +2036,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = and_token, .op = ast.Node.InfixOp.Op.BoolAnd, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BoolAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .ComparisonExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2025,13 +2064,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToComparison(token_ptr.id)) |comp_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = comp_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .ComparisonExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2052,13 +2092,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = pipe, .op = ast.Node.InfixOp.Op.BitOr, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BinaryOrExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .BinaryXorExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2076,13 +2117,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = caret, .op = ast.Node.InfixOp.Op.BitXor, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BinaryXorExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .BinaryAndExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2100,13 +2142,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = ampersand, .op = ast.Node.InfixOp.Op.BitAnd, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BinaryAndExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .BitShiftExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2127,13 +2170,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = bitshift_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .BitShiftExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2157,13 +2201,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToAddition(token_ptr.id)) |add_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = add_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .AdditionExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2187,13 +2232,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToMultiply(token_ptr.id)) |mult_id| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = mult_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .MultiplyExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } }); @@ -2215,12 +2261,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (tok_it.peek().?.id == Token.Id.Period) { - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, .rtoken = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; @@ -2234,12 +2281,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) }, .rtoken = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .CurlySuffixExpressionEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .IfToken = Token.Id.LBrace }); @@ -2263,13 +2311,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const lhs = opt_ctx.get() orelse continue; if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = bang, .op = ast.Node.InfixOp.Op.ErrorUnion, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .TypeExprEnd = opt_ctx.toRequired() }) catch unreachable; try stack.append(State{ .PrefixOpExpression = OptionalCtx{ .Required = &node.rhs } }); @@ -2282,22 +2331,24 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_index = token.index; const token_ptr = token.ptr; if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| { - var node = try arena.create(ast.Node.PrefixOp{ + var node = try arena.create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, .op_token = token_index, .op = prefix_id, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); // Treat '**' token as two pointer types if (token_ptr.id == Token.Id.AsteriskAsterisk) { - const child = try arena.create(ast.Node.PrefixOp{ + const child = try arena.create(ast.Node.PrefixOp); + child.* = ast.Node.PrefixOp{ .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, .op_token = token_index, .op = prefix_id, .rhs = undefined, - }); + }; node.rhs = &child.base; node = child; } @@ -2316,12 +2367,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.SuffixOpExpressionBegin => |opt_ctx| { if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| { - const async_node = try arena.create(ast.Node.AsyncAttribute{ + const async_node = try arena.create(ast.Node.AsyncAttribute); + async_node.* = ast.Node.AsyncAttribute{ .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute }, .async_token = async_token, .allocator_type = null, .rangle_bracket = null, - }); + }; stack.append(State{ .AsyncEnd = AsyncEndCtx{ .ctx = opt_ctx, @@ -2347,7 +2399,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { const token_ptr = token.ptr; switch (token_ptr.id) { Token.Id.LParen => { - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op{ @@ -2357,7 +2410,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, }, .rtoken = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; @@ -2371,12 +2424,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LBracket => { - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined }, .rtoken = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; @@ -2386,34 +2440,37 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }, Token.Id.Period => { if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| { - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op.Deref, .rtoken = asterisk_token, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; continue; } if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| { - const node = try arena.create(ast.Node.SuffixOp{ + const node = try arena.create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, .op = ast.Node.SuffixOp.Op.UnwrapOptional, .rtoken = question_token, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; continue; } - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, .op_token = token_index, .op = ast.Node.InfixOp.Op.Period, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; @@ -2467,11 +2524,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_promise => { - const node = try arena.create(ast.Node.PromiseType{ + const node = try arena.create(ast.Node.PromiseType); + node.* = ast.Node.PromiseType{ .base = ast.Node{ .id = ast.Node.Id.PromiseType }, .promise_token = token.index, .result = null, - }); + }; opt_ctx.store(&node.base); const next_token = nextToken(&tok_it, &tree); const next_token_index = next_token.index; @@ -2493,12 +2551,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LParen => { - const node = try arena.create(ast.Node.GroupedExpression{ + const node = try arena.create(ast.Node.GroupedExpression); + node.* = ast.Node.GroupedExpression{ .base = ast.Node{ .id = ast.Node.Id.GroupedExpression }, .lparen = token.index, .expr = undefined, .rparen = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ @@ -2511,12 +2570,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Builtin => { - const node = try arena.create(ast.Node.BuiltinCall{ + const node = try arena.create(ast.Node.BuiltinCall); + node.* = ast.Node.BuiltinCall{ .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, .builtin_token = token.index, .params = ast.Node.BuiltinCall.ParamList.init(arena), .rparen_token = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ @@ -2530,12 +2590,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.LBracket => { - const node = try arena.create(ast.Node.PrefixOp{ + const node = try arena.create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ .base = ast.Node{ .id = ast.Node.Id.PrefixOp }, .op_token = token.index, .op = undefined, .rhs = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ .SliceOrArrayType = node }) catch unreachable; @@ -2593,7 +2654,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_fn => { - const fn_proto = try arena.create(ast.Node.FnProto{ + const fn_proto = try arena.create(ast.Node.FnProto); + fn_proto.* = ast.Node.FnProto{ .base = ast.Node{ .id = ast.Node.Id.FnProto }, .doc_comments = null, .visib_token = null, @@ -2609,13 +2671,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .lib_name = null, .align_expr = null, .section_expr = null, - }); + }; opt_ctx.store(&fn_proto.base); stack.append(State{ .FnProto = fn_proto }) catch unreachable; continue; }, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => { - const fn_proto = try arena.create(ast.Node.FnProto{ + const fn_proto = try arena.create(ast.Node.FnProto); + fn_proto.* = ast.Node.FnProto{ .base = ast.Node{ .id = ast.Node.Id.FnProto }, .doc_comments = null, .visib_token = null, @@ -2631,7 +2694,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .lib_name = null, .align_expr = null, .section_expr = null, - }); + }; opt_ctx.store(&fn_proto.base); stack.append(State{ .FnProto = fn_proto }) catch unreachable; try stack.append(State{ @@ -2643,7 +2706,8 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; }, Token.Id.Keyword_asm => { - const node = try arena.create(ast.Node.Asm{ + const node = try arena.create(ast.Node.Asm); + node.* = ast.Node.Asm{ .base = ast.Node{ .id = ast.Node.Id.Asm }, .asm_token = token.index, .volatile_token = null, @@ -2652,7 +2716,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .inputs = ast.Node.Asm.InputList.init(arena), .clobbers = ast.Node.Asm.ClobberList.init(arena), .rparen = undefined, - }); + }; opt_ctx.store(&node.base); stack.append(State{ @@ -2701,13 +2765,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.ErrorTypeOrSetDecl => |ctx| { if (eatToken(&tok_it, &tree, Token.Id.LBrace) == null) { - const node = try arena.create(ast.Node.InfixOp{ + const node = try arena.create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = &(try createLiteral(arena, ast.Node.ErrorType, ctx.error_token)).base, .op_token = undefined, .op = ast.Node.InfixOp.Op.Period, .rhs = undefined, - }); + }; ctx.opt_ctx.store(&node.base); stack.append(State{ .Identifier = OptionalCtx{ .Required = &node.rhs } }) catch unreachable; try stack.append(State{ @@ -2719,12 +2784,13 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { continue; } - const node = try arena.create(ast.Node.ErrorSetDecl{ + const node = try arena.create(ast.Node.ErrorSetDecl); + node.* = ast.Node.ErrorSetDecl{ .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl }, .error_token = ctx.error_token, .decls = ast.Node.ErrorSetDecl.DeclList.init(arena), .rbrace_token = undefined, - }); + }; ctx.opt_ctx.store(&node.base); stack.append(State{ @@ -2785,11 +2851,12 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { return tree; } - const node = try arena.create(ast.Node.ErrorTag{ + const node = try arena.create(ast.Node.ErrorTag); + node.* = ast.Node.ErrorTag{ .base = ast.Node{ .id = ast.Node.Id.ErrorTag }, .doc_comments = comments, .name_token = ident_token_index, - }); + }; node_ptr.* = &node.base; continue; }, @@ -3129,10 +3196,11 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as if (result.*) |comment_node| { break :blk comment_node; } else { - const comment_node = try arena.create(ast.Node.DocComment{ + const comment_node = try arena.create(ast.Node.DocComment); + comment_node.* = ast.Node.DocComment{ .base = ast.Node{ .id = ast.Node.Id.DocComment }, .lines = ast.Node.DocComment.LineList.init(arena), - }); + }; result.* = comment_node; break :blk comment_node; } @@ -3158,10 +3226,11 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base; }, Token.Id.MultilineStringLiteralLine => { - const node = try arena.create(ast.Node.MultilineStringLiteral{ + const node = try arena.create(ast.Node.MultilineStringLiteral); + node.* = ast.Node.MultilineStringLiteral{ .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral }, .lines = ast.Node.MultilineStringLiteral.LineList.init(arena), - }); + }; try node.lines.push(token_index); while (true) { const multiline_str = nextToken(tok_it, tree); @@ -3186,25 +3255,27 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: OptionalCtx, token_ptr: Token, token_index: TokenIndex) !bool { switch (token_ptr.id) { Token.Id.Keyword_suspend => { - const node = try arena.create(ast.Node.Suspend{ + const node = try arena.create(ast.Node.Suspend); + node.* = ast.Node.Suspend{ .base = ast.Node{ .id = ast.Node.Id.Suspend }, .suspend_token = token_index, .body = null, - }); + }; ctx.store(&node.base); stack.append(State{ .SuspendBody = node }) catch unreachable; return true; }, Token.Id.Keyword_if => { - const node = try arena.create(ast.Node.If{ + const node = try arena.create(ast.Node.If); + node.* = ast.Node.If{ .base = ast.Node{ .id = ast.Node.Id.If }, .if_token = token_index, .condition = undefined, .payload = null, .body = undefined, .@"else" = null, - }); + }; ctx.store(&node.base); stack.append(State{ .Else = &node.@"else" }) catch unreachable; @@ -3238,13 +3309,14 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti return true; }, Token.Id.Keyword_switch => { - const node = try arena.create(ast.Node.Switch{ + const node = try arena.create(ast.Node.Switch); + node.* = ast.Node.Switch{ .base = ast.Node{ .id = ast.Node.Id.Switch }, .switch_token = token_index, .expr = undefined, .cases = ast.Node.Switch.CaseList.init(arena), .rbrace = undefined, - }); + }; ctx.store(&node.base); stack.append(State{ @@ -3260,25 +3332,27 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: Opti return true; }, Token.Id.Keyword_comptime => { - const node = try arena.create(ast.Node.Comptime{ + const node = try arena.create(ast.Node.Comptime); + node.* = ast.Node.Comptime{ .base = ast.Node{ .id = ast.Node.Id.Comptime }, .comptime_token = token_index, .expr = undefined, .doc_comments = null, - }); + }; ctx.store(&node.base); try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } }); return true; }, Token.Id.LBrace => { - const block = try arena.create(ast.Node.Block{ + const block = try arena.create(ast.Node.Block); + block.* = ast.Node.Block{ .base = ast.Node{ .id = ast.Node.Id.Block }, .label = null, .lbrace = token_index, .statements = ast.Node.Block.StatementList.init(arena), .rbrace = undefined, - }); + }; ctx.store(&block.base); stack.append(State{ .Block = block }) catch unreachable; return true; @@ -3412,10 +3486,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { } fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T { - return arena.create(T{ + const result = try arena.create(T); + result.* = T{ .base = ast.Node{ .id = ast.Node.typeToId(T) }, .token = token_index, - }); + }; + return result; } fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: OptionalCtx, comptime T: type, token_index: TokenIndex) !*T { diff --git a/test/tests.zig b/test/tests.zig index 73d4644d18..548496fa2f 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -48,13 +48,14 @@ const test_targets = []TestTarget{ const max_stdout_size = 1 * 1024 * 1024; // 1 MB pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(CompareOutputContext{ + const cases = b.allocator.create(CompareOutputContext) catch unreachable; + cases.* = CompareOutputContext{ .b = b, .step = b.step("test-compare-output", "Run the compare output tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, - }) catch unreachable; + }; compare_output.addCases(cases); @@ -62,13 +63,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: } pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(CompareOutputContext{ + const cases = b.allocator.create(CompareOutputContext) catch unreachable; + cases.* = CompareOutputContext{ .b = b, .step = b.step("test-runtime-safety", "Run the runtime safety tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, - }) catch unreachable; + }; runtime_safety.addCases(cases); @@ -76,13 +78,14 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: } pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(CompileErrorContext{ + const cases = b.allocator.create(CompileErrorContext) catch unreachable; + cases.* = CompileErrorContext{ .b = b, .step = b.step("test-compile-errors", "Run the compile error tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, - }) catch unreachable; + }; compile_errors.addCases(cases); @@ -90,13 +93,14 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: } pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(BuildExamplesContext{ + const cases = b.allocator.create(BuildExamplesContext) catch unreachable; + cases.* = BuildExamplesContext{ .b = b, .step = b.step("test-build-examples", "Build the examples"), .test_index = 0, .test_filter = test_filter, .modes = modes, - }) catch unreachable; + }; build_examples.addCases(cases); @@ -119,13 +123,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M } pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { - const cases = b.allocator.create(CompareOutputContext{ + const cases = b.allocator.create(CompareOutputContext) catch unreachable; + cases.* = CompareOutputContext{ .b = b, .step = b.step("test-asm-link", "Run the assemble and link tests"), .test_index = 0, .test_filter = test_filter, .modes = modes, - }) catch unreachable; + }; assemble_and_link.addCases(cases); @@ -133,12 +138,13 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, mode } pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { - const cases = b.allocator.create(TranslateCContext{ + const cases = b.allocator.create(TranslateCContext) catch unreachable; + cases.* = TranslateCContext{ .b = b, .step = b.step("test-translate-c", "Run the C transation tests"), .test_index = 0, .test_filter = test_filter, - }) catch unreachable; + }; translate_c.addCases(cases); @@ -146,12 +152,13 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St } pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { - const cases = b.allocator.create(GenHContext{ + const cases = b.allocator.create(GenHContext) catch unreachable; + cases.* = GenHContext{ .b = b, .step = b.step("test-gen-h", "Run the C header file generation tests"), .test_index = 0, .test_filter = test_filter, - }) catch unreachable; + }; gen_h.addCases(cases); @@ -244,7 +251,8 @@ pub const CompareOutputContext = struct { pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep { const allocator = context.b.allocator; - const ptr = allocator.create(RunCompareOutputStep{ + const ptr = allocator.create(RunCompareOutputStep) catch unreachable; + ptr.* = RunCompareOutputStep{ .context = context, .exe_path = exe_path, .name = name, @@ -252,7 +260,7 @@ pub const CompareOutputContext = struct { .test_index = context.test_index, .step = build.Step.init("RunCompareOutput", allocator, make), .cli_args = cli_args, - }) catch unreachable; + }; context.test_index += 1; return ptr; } @@ -331,13 +339,14 @@ pub const CompareOutputContext = struct { pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep { const allocator = context.b.allocator; - const ptr = allocator.create(RuntimeSafetyRunStep{ + const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable; + ptr.* = RuntimeSafetyRunStep{ .context = context, .exe_path = exe_path, .name = name, .test_index = context.test_index, .step = build.Step.init("RuntimeSafetyRun", allocator, make), - }) catch unreachable; + }; context.test_index += 1; return ptr; @@ -542,14 +551,15 @@ pub const CompileErrorContext = struct { pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep { const allocator = context.b.allocator; - const ptr = allocator.create(CompileCmpOutputStep{ + const ptr = allocator.create(CompileCmpOutputStep) catch unreachable; + ptr.* = CompileCmpOutputStep{ .step = build.Step.init("CompileCmpOutput", allocator, make), .context = context, .name = name, .test_index = context.test_index, .case = case, .build_mode = build_mode, - }) catch unreachable; + }; context.test_index += 1; return ptr; @@ -661,13 +671,14 @@ pub const CompileErrorContext = struct { } pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { - const tc = self.b.allocator.create(TestCase{ + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ .name = name, .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_errors = ArrayList([]const u8).init(self.b.allocator), .link_libc = false, .is_exe = false, - }) catch unreachable; + }; tc.addSourceFile(".tmp_source.zig", source); comptime var arg_i = 0; @@ -821,13 +832,14 @@ pub const TranslateCContext = struct { pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep { const allocator = context.b.allocator; - const ptr = allocator.create(TranslateCCmpOutputStep{ + const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable; + ptr.* = TranslateCCmpOutputStep{ .step = build.Step.init("ParseCCmpOutput", allocator, make), .context = context, .name = name, .test_index = context.test_index, .case = case, - }) catch unreachable; + }; context.test_index += 1; return ptr; @@ -928,12 +940,13 @@ pub const TranslateCContext = struct { } pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { - const tc = self.b.allocator.create(TestCase{ + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ .name = name, .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_lines = ArrayList([]const u8).init(self.b.allocator), .allow_warnings = allow_warnings, - }) catch unreachable; + }; tc.addSourceFile(filename, source); comptime var arg_i = 0; @@ -1015,14 +1028,15 @@ pub const GenHContext = struct { pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep { const allocator = context.b.allocator; - const ptr = allocator.create(GenHCmpOutputStep{ + const ptr = allocator.create(GenHCmpOutputStep) catch unreachable; + ptr.* = GenHCmpOutputStep{ .step = build.Step.init("ParseCCmpOutput", allocator, make), .context = context, .h_path = h_path, .name = name, .test_index = context.test_index, .case = case, - }) catch unreachable; + }; context.test_index += 1; return ptr; @@ -1062,11 +1076,12 @@ pub const GenHContext = struct { } pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase { - const tc = self.b.allocator.create(TestCase{ + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ .name = name, .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_lines = ArrayList([]const u8).init(self.b.allocator), - }) catch unreachable; + }; tc.addSourceFile(filename, source); comptime var arg_i = 0; From 67bd45f0cf1b452cf8de5a016bc6ff2f85393d70 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Feb 2019 15:24:06 -0500 Subject: [PATCH 134/218] adjustments to std.mem split / separate * rename std.mem.split to std.mem.tokenize * add future deprecation notice to docs * (unrelated) add note to std.os.path.resolve docs * std.mem.separate - assert delimiter.len not zero * fix implementation of std.mem.separate to respect the delimiter * separate the two iterators to different structs --- build.zig | 16 ++-- src-self-hosted/libc_installation.zig | 8 +- src-self-hosted/main.zig | 2 +- std/build.zig | 6 +- std/mem.zig | 129 ++++++++++++++------------ std/os/child_process.zig | 2 +- std/os/index.zig | 2 +- std/os/path.zig | 44 ++++----- 8 files changed, 112 insertions(+), 97 deletions(-) diff --git a/build.zig b/build.zig index d99165a6de..a41a5f808b 100644 --- a/build.zig +++ b/build.zig @@ -189,14 +189,14 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { const prefix_output = try b.exec([][]const u8{ llvm_config_exe, "--prefix" }); var result = LibraryDep{ - .prefix = mem.split(prefix_output, " \r\n").next().?, + .prefix = mem.tokenize(prefix_output, " \r\n").next().?, .libs = ArrayList([]const u8).init(b.allocator), .system_libs = ArrayList([]const u8).init(b.allocator), .includes = ArrayList([]const u8).init(b.allocator), .libdirs = ArrayList([]const u8).init(b.allocator), }; { - var it = mem.split(libs_output, " \r\n"); + var it = mem.tokenize(libs_output, " \r\n"); while (it.next()) |lib_arg| { if (mem.startsWith(u8, lib_arg, "-l")) { try result.system_libs.append(lib_arg[2..]); @@ -210,7 +210,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { } } { - var it = mem.split(includes_output, " \r\n"); + var it = mem.tokenize(includes_output, " \r\n"); while (it.next()) |include_arg| { if (mem.startsWith(u8, include_arg, "-I")) { try result.includes.append(include_arg[2..]); @@ -220,7 +220,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { } } { - var it = mem.split(libdir_output, " \r\n"); + var it = mem.tokenize(libdir_output, " \r\n"); while (it.next()) |libdir| { if (mem.startsWith(u8, libdir, "-L")) { try result.libdirs.append(libdir[2..]); @@ -233,7 +233,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { } pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { - var it = mem.split(stdlib_files, ";"); + var it = mem.tokenize(stdlib_files, ";"); while (it.next()) |stdlib_file| { const src_path = os.path.join(b.allocator, "std", stdlib_file) catch unreachable; const dest_path = os.path.join(b.allocator, "lib", "zig", "std", stdlib_file) catch unreachable; @@ -242,7 +242,7 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { } pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { - var it = mem.split(c_header_files, ";"); + var it = mem.tokenize(c_header_files, ";"); while (it.next()) |c_header_file| { const src_path = os.path.join(b.allocator, "c_headers", c_header_file) catch unreachable; const dest_path = os.path.join(b.allocator, "lib", "zig", "include", c_header_file) catch unreachable; @@ -277,7 +277,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp"); if (ctx.lld_include_dir.len != 0) { exe.addIncludeDir(ctx.lld_include_dir); - var it = mem.split(ctx.lld_libraries, ";"); + var it = mem.tokenize(ctx.lld_libraries, ";"); while (it.next()) |lib| { exe.addObjectFile(lib); } @@ -334,7 +334,7 @@ fn addCxxKnownPath( ctx.cxx_compiler, b.fmt("-print-file-name={}", objname), }); - const path_unpadded = mem.split(path_padded, "\r\n").next().?; + const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?; if (mem.eql(u8, path_unpadded, objname)) { if (errtxt) |msg| { warn("{}", msg); diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index 1c5d111c5a..18d2daf0c2 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -57,10 +57,10 @@ pub const LibCInstallation = struct { const contents = try std.io.readFileAlloc(allocator, libc_file); defer allocator.free(contents); - var it = std.mem.split(contents, "\n"); + var it = std.mem.tokenize(contents, "\n"); while (it.next()) |line| { if (line.len == 0 or line[0] == '#') continue; - var line_it = std.mem.split(line, "="); + var line_it = std.mem.separate(line, "="); const name = line_it.next() orelse { try stderr.print("missing equal sign after field name\n"); return error.ParseError; @@ -213,7 +213,7 @@ pub const LibCInstallation = struct { }, } - var it = std.mem.split(exec_result.stderr, "\n\r"); + var it = std.mem.tokenize(exec_result.stderr, "\n\r"); var search_paths = std.ArrayList([]const u8).init(loop.allocator); defer search_paths.deinit(); while (it.next()) |line| { @@ -410,7 +410,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo return error.CCompilerCrashed; }, } - var it = std.mem.split(exec_result.stdout, "\n\r"); + var it = std.mem.tokenize(exec_result.stdout, "\n\r"); const line = it.next() orelse return error.LibCRuntimeNotFound; const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound; diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 1403ab860d..f6ee9a0513 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -351,7 +351,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co const root_name = if (provided_name) |n| n else blk: { if (root_source_file) |file| { const basename = os.path.basename(file); - var it = mem.split(basename, "."); + var it = mem.separate(basename, "."); break :blk it.next() orelse basename; } else { try stderr.write("--name [name] not provided and unable to infer\n"); diff --git a/std/build.zig b/std/build.zig index 6f58594190..5246d97339 100644 --- a/std/build.zig +++ b/std/build.zig @@ -324,7 +324,7 @@ pub const Builder = struct { fn processNixOSEnvVars(self: *Builder) void { if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { - var it = mem.split(nix_cflags_compile, " "); + var it = mem.tokenize(nix_cflags_compile, " "); while (true) { const word = it.next() orelse break; if (mem.eql(u8, word, "-isystem")) { @@ -342,7 +342,7 @@ pub const Builder = struct { assert(err == error.EnvironmentVariableNotFound); } if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { - var it = mem.split(nix_ldflags, " "); + var it = mem.tokenize(nix_ldflags, " "); while (true) { const word = it.next() orelse break; if (mem.eql(u8, word, "-rpath")) { @@ -689,7 +689,7 @@ pub const Builder = struct { if (os.path.isAbsolute(name)) { return name; } - var it = mem.split(PATH, []u8{os.path.delimiter}); + var it = mem.tokenize(PATH, []u8{os.path.delimiter}); while (it.next()) |path| { const full_path = try os.path.join(self.allocator, path, self.fmt("{}{}", name, exe_extension)); if (os.path.real(self.allocator, full_path)) |real_path| { diff --git a/std/mem.zig b/std/mem.zig index bec3816d88..26ae4ef089 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -689,58 +689,57 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) bool { } /// Returns an iterator that iterates over the slices of `buffer` that are not -/// any of the bytes in `split_bytes`. -/// split(" abc def ghi ", " ") +/// any of the bytes in `delimiter_bytes`. +/// tokenize(" abc def ghi ", " ") /// Will return slices for "abc", "def", "ghi", null, in that order. -/// If `split_bytes` does not exist in buffer, +/// If `buffer` is empty, the iterator will return null. +/// If `delimiter_bytes` does not exist in buffer, /// the iterator will return `buffer`, null, in that order. -pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { - return SplitIterator{ +/// See also the related function `separate`. +pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator { + return TokenIterator{ .index = 0, .buffer = buffer, - .split_bytes = split_bytes, - .glob = true, - .spun = false, + .delimiter_bytes = delimiter_bytes, }; } -test "mem.split" { - var it = split(" abc def ghi ", " "); +test "mem.tokenize" { + var it = tokenize(" abc def ghi ", " "); assert(eql(u8, it.next().?, "abc")); assert(eql(u8, it.next().?, "def")); assert(eql(u8, it.next().?, "ghi")); assert(it.next() == null); - it = split("..\\bob", "\\"); + it = tokenize("..\\bob", "\\"); assert(eql(u8, it.next().?, "..")); assert(eql(u8, "..", "..\\bob"[0..it.index])); assert(eql(u8, it.next().?, "bob")); assert(it.next() == null); - it = split("//a/b", "/"); + it = tokenize("//a/b", "/"); assert(eql(u8, it.next().?, "a")); assert(eql(u8, it.next().?, "b")); assert(eql(u8, "//a/b", "//a/b"[0..it.index])); assert(it.next() == null); - it = split("|", "|"); + it = tokenize("|", "|"); assert(it.next() == null); - it = split("", "|"); - assert(eql(u8, it.next().?, "")); + it = tokenize("", "|"); assert(it.next() == null); - it = split("hello", ""); + it = tokenize("hello", ""); assert(eql(u8, it.next().?, "hello")); assert(it.next() == null); - it = split("hello", " "); + it = tokenize("hello", " "); assert(eql(u8, it.next().?, "hello")); assert(it.next() == null); } -test "mem.split (multibyte)" { - var it = split("a|b,c/d e", " /,|"); +test "mem.tokenize (multibyte)" { + var it = tokenize("a|b,c/d e", " /,|"); assert(eql(u8, it.next().?, "a")); assert(eql(u8, it.next().?, "b")); assert(eql(u8, it.next().?, "c")); @@ -750,18 +749,21 @@ test "mem.split (multibyte)" { } /// Returns an iterator that iterates over the slices of `buffer` that -/// seperates by bytes in `delimiter`. +/// are separated by bytes in `delimiter`. /// separate("abc|def||ghi", "|") -/// Will return slices for "abc", "def", "", "ghi", null, in that order. +/// will return slices for "abc", "def", "", "ghi", null, in that order. /// If `delimiter` does not exist in buffer, /// the iterator will return `buffer`, null, in that order. +/// The delimiter length must not be zero. +/// See also the related function `tokenize`. +/// It is planned to rename this function to `split` before 1.0.0, like this: +/// pub fn split(buffer: []const u8, delimiter: []const u8) SplitIterator { pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { + assert(delimiter.len != 0); return SplitIterator{ .index = 0, .buffer = buffer, - .split_bytes = delimiter, - .glob = false, - .spun = false, + .delimiter = delimiter, }; } @@ -782,19 +784,15 @@ test "mem.separate" { assert(eql(u8, it.next().?, "")); assert(it.next() == null); - it = separate("hello", ""); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); - it = separate("hello", " "); assert(eql(u8, it.next().?, "hello")); assert(it.next() == null); } test "mem.separate (multibyte)" { - var it = separate("a|b,c/d e", " /,|"); + var it = separate("a, b ,, c, d, e", ", "); assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b")); + assert(eql(u8, it.next().?, "b ,")); assert(eql(u8, it.next().?, "c")); assert(eql(u8, it.next().?, "d")); assert(eql(u8, it.next().?, "e")); @@ -819,49 +817,38 @@ test "mem.endsWith" { assert(!endsWith(u8, "Bob", "Bo")); } -pub const SplitIterator = struct { +pub const TokenIterator = struct { buffer: []const u8, - split_bytes: []const u8, + delimiter_bytes: []const u8, index: usize, - glob: bool, - spun: bool, - /// Iterates and returns null or optionally a slice the next split segment - pub fn next(self: *SplitIterator) ?[]const u8 { - if (self.spun) { - if (self.index + 1 > self.buffer.len) return null; - self.index += 1; + /// Returns a slice of the next token, or null if tokenization is complete. + pub fn next(self: *TokenIterator) ?[]const u8 { + // move to beginning of token + while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} + const start = self.index; + if (start == self.buffer.len) { + return null; } - self.spun = true; + // move to end of token + while (self.index < self.buffer.len and !self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} + const end = self.index; - if (self.glob) { - while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} - } - - var cursor = self.index; - while (cursor < self.buffer.len and !self.isSplitByte(self.buffer[cursor])) : (cursor += 1) {} - - defer self.index = cursor; - - if (cursor == self.buffer.len) { - return if (self.glob and self.index == cursor and self.index > 0) null else self.buffer[self.index..]; - } - - return self.buffer[self.index..cursor]; + return self.buffer[start..end]; } /// Returns a slice of the remaining bytes. Does not affect iterator state. - pub fn rest(self: *const SplitIterator) []const u8 { + pub fn rest(self: TokenIterator) []const u8 { // move to beginning of token var index: usize = self.index; while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} return self.buffer[index..]; } - fn isSplitByte(self: *const SplitIterator, byte: u8) bool { - for (self.split_bytes) |split_byte| { - if (byte == split_byte) { + fn isSplitByte(self: TokenIterator, byte: u8) bool { + for (self.delimiter_bytes) |delimiter_byte| { + if (byte == delimiter_byte) { return true; } } @@ -869,6 +856,32 @@ pub const SplitIterator = struct { } }; +pub const SplitIterator = struct { + buffer: []const u8, + index: ?usize, + delimiter: []const u8, + + /// Returns a slice of the next field, or null if splitting is complete. + pub fn next(self: *SplitIterator) ?[]const u8 { + const start = self.index orelse return null; + const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: { + self.index = delim_start + self.delimiter.len; + break :blk delim_start; + } else blk: { + self.index = null; + break :blk self.buffer.len; + }; + return self.buffer[start..end]; + } + + /// Returns a slice of the remaining bytes. Does not affect iterator state. + pub fn rest(self: SplitIterator) []const u8 { + const end = self.buffer.len; + const start = self.index orelse end; + return self.buffer[start..end]; + } +}; + /// Naively combines a series of strings with a separator. /// Allocates memory for the result, which must be freed by the caller. pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 9f33bee905..7aa8582369 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -595,7 +595,7 @@ pub const ChildProcess = struct { const PATH = try os.getEnvVarOwned(self.allocator, "PATH"); defer self.allocator.free(PATH); - var it = mem.split(PATH, ";"); + var it = mem.tokenize(PATH, ";"); while (it.next()) |search_path| { const joined_path = try os.path.join(self.allocator, search_path, app_name); defer self.allocator.free(joined_path); diff --git a/std/os/index.zig b/std/os/index.zig index 0d0e07bfa3..451c0a3436 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -608,7 +608,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: // +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.split(PATH, ":"); + var it = mem.tokenize(PATH, ":"); var seen_eacces = false; var err: usize = undefined; while (it.next()) |search_path| { diff --git a/std/os/path.zig b/std/os/path.zig index 4d3d3d6a8b..0b960fa2da 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -184,7 +184,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { return relative_path; } - var it = mem.split(path, []u8{this_sep}); + var it = mem.tokenize(path, []u8{this_sep}); _ = (it.next() orelse return relative_path); _ = (it.next() orelse return relative_path); return WindowsPath{ @@ -202,7 +202,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { return relative_path; } - var it = mem.split(path, []u8{this_sep}); + var it = mem.tokenize(path, []u8{this_sep}); _ = (it.next() orelse return relative_path); _ = (it.next() orelse return relative_path); return WindowsPath{ @@ -264,8 +264,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { const sep1 = ns1[0]; const sep2 = ns2[0]; - var it1 = mem.split(ns1, []u8{sep1}); - var it2 = mem.split(ns2, []u8{sep2}); + var it1 = mem.tokenize(ns1, []u8{sep1}); + var it2 = mem.tokenize(ns2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. return asciiEqlIgnoreCase(it1.next().?, it2.next().?); @@ -285,8 +285,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 const sep1 = p1[0]; const sep2 = p2[0]; - var it1 = mem.split(p1, []u8{sep1}); - var it2 = mem.split(p2, []u8{sep2}); + var it1 = mem.tokenize(p1, []u8{sep1}); + var it2 = mem.tokenize(p2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?); @@ -337,6 +337,8 @@ pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 { /// If all paths are relative it uses the current working directory as a starting point. /// Each drive has its own current working directory. /// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters. +/// Note: all usage of this function should be audited due to the existence of symlinks. +/// Without performing actual syscalls, resolving `..` could be incorrect. pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { assert(is_windows); // resolveWindows called on non windows can't use getCwd @@ -416,7 +418,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { }, WindowsPath.Kind.NetworkShare => { result = try allocator.alloc(u8, max_size); - var it = mem.split(paths[first_index], "/\\"); + var it = mem.tokenize(paths[first_index], "/\\"); const server_name = it.next().?; const other_name = it.next().?; @@ -483,7 +485,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (!correct_disk_designator) { continue; } - var it = mem.split(p[parsed.disk_designator.len..], "/\\"); + var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\"); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; @@ -516,6 +518,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { /// It resolves "." and "..". /// The result does not have a trailing path separator. /// If all paths are relative it uses the current working directory as a starting point. +/// Note: all usage of this function should be audited due to the existence of symlinks. +/// Without performing actual syscalls, resolving `..` could be incorrect. pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { assert(!is_windows); // resolvePosix called on windows can't use getCwd @@ -550,7 +554,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { errdefer allocator.free(result); for (paths[first_index..]) |p, i| { - var it = mem.split(p, "/"); + var it = mem.tokenize(p, "/"); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; @@ -937,8 +941,8 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) return resolved_to; } - var from_it = mem.split(resolved_from, "/\\"); - var to_it = mem.split(resolved_to, "/\\"); + var from_it = mem.tokenize(resolved_from, "/\\"); + var to_it = mem.tokenize(resolved_to, "/\\"); while (true) { const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); const to_rest = to_it.rest(); @@ -967,14 +971,12 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) // shave off the trailing slash result_index -= 1; - if (to_rest.len > 0) { - var rest_it = mem.split(to_rest, "/\\"); - while (rest_it.next()) |to_component| { - result[result_index] = '\\'; - result_index += 1; - mem.copy(u8, result[result_index..], to_component); - result_index += to_component.len; - } + var rest_it = mem.tokenize(to_rest, "/\\"); + while (rest_it.next()) |to_component| { + result[result_index] = '\\'; + result_index += 1; + mem.copy(u8, result[result_index..], to_component); + result_index += to_component.len; } return result[0..result_index]; @@ -990,8 +992,8 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ const resolved_to = try resolvePosix(allocator, [][]const u8{to}); defer allocator.free(resolved_to); - var from_it = mem.split(resolved_from, "/"); - var to_it = mem.split(resolved_to, "/"); + var from_it = mem.tokenize(resolved_from, "/"); + var to_it = mem.tokenize(resolved_to, "/"); while (true) { const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); const to_rest = to_it.rest(); From 8c6fa982cd0a02775264b616c37da9907cc603bb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Feb 2019 20:30:00 -0500 Subject: [PATCH 135/218] SIMD: array to vector, vector to array, wrapping int add also vectors and arrays now use the same ConstExprVal representation See #903 --- src/all_types.hpp | 20 ++- src/analyze.cpp | 178 +++++++++---------- src/analyze.hpp | 1 + src/codegen.cpp | 98 ++++++++--- src/ir.cpp | 291 ++++++++++++++++++++------------ src/ir_print.cpp | 18 ++ test/stage1/behavior.zig | 1 + test/stage1/behavior/vector.zig | 20 +++ 8 files changed, 403 insertions(+), 224 deletions(-) create mode 100644 test/stage1/behavior/vector.zig diff --git a/src/all_types.hpp b/src/all_types.hpp index 3fc6772b31..c4c9e13cfb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -252,10 +252,6 @@ struct ConstArgTuple { size_t end_index; }; -struct ConstVector { - ConstExprValue *elements; -}; - enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, @@ -322,7 +318,6 @@ struct ConstExprValue { ConstPtrValue x_ptr; ImportTableEntry *x_import; ConstArgTuple x_arg_tuple; - ConstVector x_vector; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -2239,6 +2234,8 @@ enum IrInstructionId { IrInstructionIdToBytes, IrInstructionIdFromBytes, IrInstructionIdCheckRuntimeScope, + IrInstructionIdVectorToArray, + IrInstructionIdArrayToVector, }; struct IrInstruction { @@ -3368,6 +3365,19 @@ struct IrInstructionBitReverse { IrInstruction *op; }; +struct IrInstructionArrayToVector { + IrInstruction base; + + IrInstruction *array; +}; + +struct IrInstructionVectorToArray { + IrInstruction base; + + IrInstruction *vector; + LLVMValueRef tmp_ptr; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 99378eb7a8..ff961a7044 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4457,7 +4457,15 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return new_entry; } +bool is_valid_vector_elem_type(ZigType *elem_type) { + return elem_type->id == ZigTypeIdInt || + elem_type->id == ZigTypeIdFloat || + get_codegen_ptr_type(elem_type) != nullptr; +} + ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { + assert(is_valid_vector_elem_type(elem_type)); + TypeId type_id = {}; type_id.id = ZigTypeIdVector; type_id.data.vector.len = len; @@ -5749,6 +5757,28 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { zig_unreachable(); } +static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprValue *b, size_t len) { + assert(a->data.x_array.special != ConstArraySpecialUndef); + assert(b->data.x_array.special != ConstArraySpecialUndef); + if (a->data.x_array.special == ConstArraySpecialBuf && + b->data.x_array.special == ConstArraySpecialBuf) + { + return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); + } + expand_undef_array(g, a); + expand_undef_array(g, b); + + ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; + ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; + + for (size_t i = 0; i < len; i += 1) { + if (!const_values_equal(g, &a_elems[i], &b_elems[i])) + return false; + } + + return true; +} + bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { assert(a->type->id == b->type->id); assert(a->special == ConstValSpecialStatic); @@ -5803,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdPointer: case ZigTypeIdFn: return const_values_equal_ptr(a, b); + case ZigTypeIdVector: + assert(a->type->data.vector.len == b->type->data.vector.len); + return const_values_equal_array(g, a, b, a->type->data.vector.len); case ZigTypeIdArray: { assert(a->type->data.array.len == b->type->data.array.len); - assert(a->data.x_array.special != ConstArraySpecialUndef); - assert(b->data.x_array.special != ConstArraySpecialUndef); - if (a->data.x_array.special == ConstArraySpecialBuf && - b->data.x_array.special == ConstArraySpecialBuf) - { - return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); - } - expand_undef_array(g, a); - expand_undef_array(g, b); - - size_t len = a->type->data.array.len; - ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; - ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; + return const_values_equal_array(g, a, b, a->type->data.array.len); } case ZigTypeIdStruct: for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { @@ -5853,20 +5867,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { 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; - case ZigTypeIdVector: { - assert(a->type->data.vector.len == b->type->data.vector.len); - - size_t len = a->type->data.vector.len; - ConstExprValue *a_elems = a->data.x_vector.elements; - ConstExprValue *b_elems = b->data.x_vector.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; - } case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -5985,6 +5985,40 @@ static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const } } +static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + buf_append_str(buf, "undefined"); + return; + case ConstArraySpecialBuf: { + Buf *array_buf = const_val->data.x_array.data.s_buf; + buf_append_char(buf, '"'); + for (size_t i = 0; i < buf_len(array_buf); i += 1) { + uint8_t c = buf_ptr(array_buf)[i]; + if (c == '"') { + buf_append_str(buf, "\\\""); + } else { + buf_append_char(buf, c); + } + } + buf_append_char(buf, '"'); + return; + } + case ConstArraySpecialNone: { + buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name)); + for (uint64_t i = 0; i < len; i += 1) { + if (i != 0) + buf_appendf(buf, ","); + ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; + render_const_value(g, buf, child_value); + } + buf_appendf(buf, "}"); + return; + } + } + zig_unreachable(); +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -6065,51 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdPointer: return render_const_val_ptr(g, buf, const_val, type_entry); + case ZigTypeIdVector: + return render_const_val_array(g, buf, const_val, type_entry->data.vector.len); case ZigTypeIdArray: - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - buf_append_str(buf, "undefined"); - return; - case ConstArraySpecialBuf: { - Buf *array_buf = const_val->data.x_array.data.s_buf; - buf_append_char(buf, '"'); - for (size_t i = 0; i < buf_len(array_buf); i += 1) { - uint8_t c = buf_ptr(array_buf)[i]; - if (c == '"') { - buf_append_str(buf, "\\\""); - } else { - buf_append_char(buf, c); - } - } - buf_append_char(buf, '"'); - return; - } - case ConstArraySpecialNone: { - buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); - uint64_t len = type_entry->data.array.len; - for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; - render_const_value(g, buf, child_value); - } - buf_appendf(buf, "}"); - return; - } - } - zig_unreachable(); - case ZigTypeIdVector: { - buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); - uint64_t len = type_entry->data.vector.len; - for (uint32_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_vector.elements[i]; - render_const_value(g, buf, child_value); - } - buf_appendf(buf, "}"); - return; - } + return render_const_val_array(g, buf, const_val, type_entry->data.array.len); case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -6379,7 +6372,17 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { - assert(const_val->type->id == ZigTypeIdArray); + size_t elem_count; + ZigType *elem_type; + if (const_val->type->id == ZigTypeIdArray) { + elem_count = const_val->type->data.array.len; + elem_type = const_val->type->data.array.child_type; + } else if (const_val->type->id == ZigTypeIdVector) { + elem_count = const_val->type->data.vector.len; + elem_type = const_val->type->data.vector.elem_type; + } else { + zig_unreachable(); + } if (const_val->special == ConstValSpecialUndef) { const_val->special = ConstValSpecialStatic; const_val->data.x_array.special = ConstArraySpecialUndef; @@ -6389,18 +6392,14 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { return; case ConstArraySpecialUndef: { const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; - element_val->type = const_val->type->data.array.child_type; + element_val->type = elem_type; init_const_undefined(g, element_val); - ConstParent *parent = get_const_val_parent(g, element_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = const_val; - parent->data.p_array.elem_index = i; - } + element_val->parent.id = ConstParentIdArray; + element_val->parent.data.p_array.array_val = const_val; + element_val->parent.data.p_array.elem_index = i; } return; } @@ -6411,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { g->string_literals_table.maybe_remove(buf); const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; assert(elem_count == buf_len(buf)); const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { @@ -6419,6 +6417,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { this_char->special = ConstValSpecialStatic; this_char->type = g->builtin_types.entry_u8; bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); + this_char->parent.id = ConstParentIdArray; + this_char->parent.data.p_array.array_val = const_val; + this_char->parent.data.p_array.elem_index = i; } return; } @@ -6426,6 +6427,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { zig_unreachable(); } +// Deprecated. Reference the parent field directly. ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { return &value->parent; } diff --git a/src/analyze.hpp b/src/analyze.hpp index da5265a594..f558fa44b0 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -74,6 +74,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); bool is_ref(ZigType *type_entry); 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); diff --git a/src/codegen.cpp b/src/codegen.cpp index b73fda59d1..de2222afb7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1921,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { } static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { - assert(alignment > 0); LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); - LLVMSetAlignment(result, alignment); + LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment); return result; } @@ -3246,6 +3245,22 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); } +static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return true; + case ConstArraySpecialBuf: + return false; + case ConstArraySpecialNone: + for (size_t i = 0; i < len; i += 1) { + if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) + return false; + } + return true; + } + zig_unreachable(); +} + static bool value_is_all_undef(ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -3260,19 +3275,9 @@ static bool value_is_all_undef(ConstExprValue *const_val) { } return true; } else if (const_val->type->id == ZigTypeIdArray) { - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return true; - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (size_t i = 0; i < const_val->type->data.array.len; i += 1) { - if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) - return false; - } - return true; - } - zig_unreachable(); + return value_is_all_undef_array(const_val, const_val->type->data.array.len); + } else if (const_val->type->id == ZigTypeIdVector) { + return value_is_all_undef_array(const_val, const_val->type->data.vector.len); } else { return false; } @@ -5194,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executable, + IrInstructionVectorToArray *instruction) +{ + ZigType *array_type = instruction->base.value.type; + assert(array_type->id == ZigTypeIdArray); + assert(handle_is_ptr(array_type)); + assert(instruction->tmp_ptr); + LLVMValueRef vector = ir_llvm_value(g, instruction->vector); + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMPointerType(instruction->vector->value.type->type_ref, 0), ""); + gen_store_untyped(g, vector, casted_ptr, 0, false); + return instruction->tmp_ptr; +} + +static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, + IrInstructionArrayToVector *instruction) +{ + ZigType *vector_type = instruction->base.value.type; + assert(vector_type->id == ZigTypeIdVector); + assert(!handle_is_ptr(vector_type)); + LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, + LLVMPointerType(vector_type->type_ref, 0), ""); + return gen_load_untyped(g, casted_ptr, 0, false, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5439,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); case IrInstructionIdBitReverse: return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); + case IrInstructionIdArrayToVector: + return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); + case IrInstructionIdVectorToArray: + return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); } zig_unreachable(); } @@ -6016,14 +6051,32 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true); } } + zig_unreachable(); } case ZigTypeIdVector: { uint32_t len = type_entry->data.vector.len; - LLVMValueRef *values = allocate(len); - for (uint32_t i = 0; i < len; i += 1) { - values[i] = gen_const_val(g, &const_val->data.x_vector.elements[i], ""); + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return LLVMGetUndef(type_entry->type_ref); + case ConstArraySpecialNone: { + LLVMValueRef *values = allocate(len); + for (uint64_t i = 0; i < len; i += 1) { + ConstExprValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; + values[i] = gen_const_val(g, elem_value, ""); + } + return LLVMConstVector(values, len); + } + case ConstArraySpecialBuf: { + Buf *buf = const_val->data.x_array.data.s_buf; + assert(buf_len(buf) == len); + LLVMValueRef *values = allocate(len); + for (uint64_t i = 0; i < len; i += 1) { + values[i] = LLVMConstInt(g->builtin_types.entry_u8->type_ref, buf_ptr(buf)[i], false); + } + return LLVMConstVector(values, len); + } } - return LLVMConstVector(values, len); + zig_unreachable(); } case ZigTypeIdUnion: { @@ -6467,6 +6520,7 @@ static void do_code_gen(CodeGen *g) { IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); LLVMValueRef *slot; ZigType *slot_type = instruction->value.type; + uint32_t alignment_bytes = 0; if (instruction->id == IrInstructionIdCast) { IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; slot = &cast_instruction->tmp_ptr; @@ -6502,10 +6556,14 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdCmpxchgGen) { IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdVectorToArray) { + IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; + alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); + slot = &vector_to_array_instruction->tmp_ptr; } else { zig_unreachable(); } - *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type)); + *slot = build_alloca(g, slot_type, "", alignment_bytes); } ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); diff --git a/src/ir.cpp b/src/ir.cpp index 3d3c501df3..3cbbdc8103 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -168,6 +168,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); +static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -899,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop return IrInstructionIdCheckRuntimeScope; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorToArray *) { + return IrInstructionIdVectorToArray; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) { + return IrInstructionIdArrayToVector; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2821,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *vector, ZigType *result_type) +{ + IrInstructionVectorToArray *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->vector = vector; + + ir_ref_instruction(vector, ira->new_irb.current_basic_block); + + ir_add_alloca(ira, &instruction->base, result_type); + + return &instruction->base; +} + +static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *array, ZigType *result_type) +{ + IrInstructionArrayToVector *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->array = array; + + ir_ref_instruction(array, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -8270,6 +8307,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); + assert(const_val_is_int || const_val_is_float); if (other_type->id == ZigTypeIdFloat) { if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { @@ -10714,6 +10752,32 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } } +static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *array, ZigType *vector_type) +{ + if (instr_is_comptime(array)) { + // arrays and vectors have the same ConstExprValue representation + IrInstruction *result = ir_const(ira, source_instr, vector_type); + copy_const_val(&result->value, &array->value, false); + result->value.type = vector_type; + return result; + } + return ir_build_array_to_vector(ira, source_instr, array, vector_type); +} + +static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *vector, ZigType *array_type) +{ + if (instr_is_comptime(vector)) { + // arrays and vectors have the same ConstExprValue representation + IrInstruction *result = ir_const(ira, source_instr, array_type); + copy_const_val(&result->value, &vector->value, false); + result->value.type = array_type; + return result; + } + return ir_build_vector_to_array(ira, source_instr, vector, array_type); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, ZigType *wanted_type, IrInstruction *value) { @@ -11102,6 +11166,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } + // cast from @Vector(N, T) to [N]T + if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector && + wanted_type->data.array.len == actual_type->data.vector.len && + types_match_const_cast_only(ira, wanted_type->data.array.child_type, + actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) + { + return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type); + } + + // cast from [N]T to @Vector(N, T) + if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector && + actual_type->data.array.len == wanted_type->data.vector.len && + types_match_const_cast_only(ira, actual_type->data.array.child_type, + wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) + { + return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); + } // cast from undefined to anything if (actual_type->id == ZigTypeIdUndefined) { @@ -11780,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * return result; } -static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, - IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) +static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry, + ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) { bool is_int; bool is_float; @@ -11803,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) { - return ErrorDivByZero; + return ir_add_error(ira, source_instr, buf_sprintf("division by zero")); } if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { - return ErrorNegativeDenominator; + return ir_add_error(ira, source_instr, buf_sprintf("negative denominator")); } switch (op_id) { @@ -11852,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, BigInt orig_bigint; bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { - return ErrorShiftedOutOneBits; + return ir_add_error(ira, source_instr, buf_sprintf("exact shift shifted out 1 bits")); } break; } @@ -11920,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, BigInt remainder; bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); if (bigint_cmp_zero(&remainder) != CmpEQ) { - return ErrorExactDivRemainder; + return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); } } else { float_div_trunc(out_val, op1_val, op2_val); ConstExprValue remainder; float_rem(&remainder, op1_val, op2_val); if (float_cmp_zero(&remainder) != CmpEQ) { - return ErrorExactDivRemainder; + return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); } } break; @@ -11951,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed)) { - return ErrorOverflow; + return ir_add_error(ira, source_instr, buf_sprintf("operation caused overflow")); } } out_val->type = type_entry; out_val->special = ConstValSpecialStatic; - return 0; + return nullptr; +} + +// This works on operands that have already been checked to be comptime known. +static IrInstruction *ir_analyze_math_op(IrAnalyze *ira, IrInstruction *source_instr, + ZigType *type_entry, ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val) +{ + IrInstruction *result_instruction = ir_const(ira, source_instr, type_entry); + ConstExprValue *out_val = &result_instruction->value; + if (type_entry->id == ZigTypeIdVector) { + expand_undef_array(ira->codegen, op1_val); + expand_undef_array(ira->codegen, op2_val); + out_val->special = ConstValSpecialUndef; + expand_undef_array(ira->codegen, out_val); + size_t len = type_entry->data.vector.len; + ZigType *scalar_type = type_entry->data.vector.elem_type; + for (size_t i = 0; i < len; i += 1) { + ConstExprValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; + assert(scalar_op1_val->type == scalar_type); + assert(scalar_op2_val->type == scalar_type); + assert(scalar_out_val->type == scalar_type); + ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type, + scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); + if (msg != nullptr) { + add_error_note(ira->codegen, msg, source_instr->source_node, + buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); + return ira->codegen->invalid_instruction; + } + } + out_val->type = type_entry; + out_val->special = ConstValSpecialStatic; + } else { + if (ir_eval_math_op_scalar(ira, source_instr, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) { + return ira->codegen->invalid_instruction; + } + } + return ir_implicit_cast(ira, result_instruction, type_entry); } static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { @@ -12029,24 +12148,7 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b if (op2_val == nullptr) return ira->codegen->invalid_instruction; - IrInstruction *result_instruction = ir_const(ira, &bin_op_instruction->base, op1->value.type); - - int err; - if ((err = ir_eval_math_op(op1->value.type, op1_val, op_id, op2_val, &result_instruction->value))) { - if (err == ErrorOverflow) { - ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorShiftedOutOneBits) { - ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits")); - return ira->codegen->invalid_instruction; - } else { - zig_unreachable(); - } - return ira->codegen->invalid_instruction; - } - - ir_num_lit_fits_in_other_type(ira, result_instruction, op1->value.type, false); - return result_instruction; + return ir_analyze_math_op(ira, &bin_op_instruction->base, op1->value.type, op1_val, op_id, op2_val); } else if (op1->value.type->id == ZigTypeIdComptimeInt) { ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); @@ -12292,30 +12394,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp if (op2_val == nullptr) return ira->codegen->invalid_instruction; - IrInstruction *result_instruction = ir_const(ira, &instruction->base, resolved_type); - - int err; - if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, &result_instruction->value))) { - if (err == ErrorDivByZero) { - ir_add_error(ira, &instruction->base, buf_sprintf("division by zero")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorOverflow) { - ir_add_error(ira, &instruction->base, buf_sprintf("operation caused overflow")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorExactDivRemainder) { - ir_add_error(ira, &instruction->base, buf_sprintf("exact division had a remainder")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorNegativeDenominator) { - ir_add_error(ira, &instruction->base, buf_sprintf("negative denominator")); - return ira->codegen->invalid_instruction; - } else { - zig_unreachable(); - } - return ira->codegen->invalid_instruction; - } - - ir_num_lit_fits_in_other_type(ira, result_instruction, resolved_type, false); - return result_instruction; + return ir_analyze_math_op(ira, &instruction->base, resolved_type, op1_val, op_id, op2_val); } IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, @@ -18745,10 +18824,7 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr if (type_is_invalid(elem_type)) return ira->codegen->invalid_instruction; - if (elem_type->id != ZigTypeIdInt && - elem_type->id != ZigTypeIdFloat && - get_codegen_ptr_type(elem_type) == nullptr) - { + if (!is_valid_vector_elem_type(elem_type)) { ir_add_error(ira, instruction->elem_type, buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", buf_ptr(&elem_type->name))); @@ -20345,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); } +static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { + size_t buf_i = 0; + // TODO optimize the buf case + expand_undef_array(codegen, val); + for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; + buf_write_value_bytes(codegen, &buf[buf_i], elem); + buf_i += type_size(codegen, elem->type); + } +} + static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { if (val->special == ConstValSpecialUndef) val->special = ConstValSpecialStatic; @@ -20390,26 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } case ZigTypeIdArray: - { - size_t buf_i = 0; - // TODO optimize the buf case - expand_undef_array(codegen, val); - for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { - ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - } - return; - case ZigTypeIdVector: { - size_t buf_i = 0; - for (uint32_t elem_i = 0; elem_i < val->type->data.vector.len; elem_i += 1) { - ConstExprValue *elem = &val->data.x_vector.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - return; - } + return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); + case ZigTypeIdVector: + return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); case ZigTypeIdStruct: zig_panic("TODO buf_write_value_bytes struct type"); case ZigTypeIdOptional: @@ -20426,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } +static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, + ConstExprValue *val, ZigType *elem_type, size_t len) +{ + Error err; + uint64_t elem_size = type_size(codegen, elem_type); + + switch (val->data.x_array.special) { + case ConstArraySpecialNone: + val->data.x_array.data.s_none.elements = create_const_vals(len); + for (size_t i = 0; i < len; i++) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = elem_type; + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) + return err; + } + return ErrorNone; + case ConstArraySpecialUndef: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); + case ConstArraySpecialBuf: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); + } + zig_unreachable(); +} + static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { Error err; assert(val->special == ConstValSpecialStatic); @@ -20464,42 +20559,12 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } - case ZigTypeIdArray: { - uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); - size_t len = val->type->data.array.len; - - switch (val->data.x_array.special) { - case ConstArraySpecialNone: - val->data.x_array.data.s_none.elements = create_const_vals(len); - for (size_t i = 0; i < len; i++) { - ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = val->type->data.array.child_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - case ConstArraySpecialUndef: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); - case ConstArraySpecialBuf: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); - } - zig_unreachable(); - } - case ZigTypeIdVector: { - uint64_t elem_size = type_size(codegen, val->type->data.vector.elem_type); - uint32_t len = val->type->data.vector.len; - - val->data.x_vector.elements = create_const_vals(len); - for (uint32_t i = 0; i < len; i += 1) { - ConstExprValue *elem = &val->data.x_vector.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = val->type->data.vector.elem_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - } + case ZigTypeIdArray: + return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, + val->type->data.array.len); + case ZigTypeIdVector: + return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, + val->type->data.vector.len); case ZigTypeIdEnum: switch (val->type->data.enumeration.layout) { case ContainerLayoutAuto: @@ -21634,6 +21699,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdDeclVarGen: case IrInstructionIdPtrCastGen: case IrInstructionIdCmpxchgGen: + case IrInstructionIdArrayToVector: + case IrInstructionIdVectorToArray: zig_unreachable(); case IrInstructionIdReturn: @@ -22129,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: + case IrInstructionIdVectorToArray: + case IrInstructionIdArrayToVector: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a1fd450b65..e19aa6dda8 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -972,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime fprintf(irp->f, ")"); } +static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *instruction) { + fprintf(irp->f, "ArrayToVector("); + ir_print_other_instruction(irp, instruction->array); + fprintf(irp->f, ")"); +} + +static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) { + fprintf(irp->f, "VectorToArray("); + ir_print_other_instruction(irp, instruction->vector); + fprintf(irp->f, ")"); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1825,6 +1837,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdDeclVarGen: ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction); break; + case IrInstructionIdArrayToVector: + ir_print_array_to_vector(irp, (IrInstructionArrayToVector *)instruction); + break; + case IrInstructionIdVectorToArray: + ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index e545a4c418..1fa00b34fd 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -74,6 +74,7 @@ comptime { _ = @import("behavior/underscore.zig"); _ = @import("behavior/union.zig"); _ = @import("behavior/var_args.zig"); + _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig new file mode 100644 index 0000000000..53c5d01381 --- /dev/null +++ b/test/stage1/behavior/vector.zig @@ -0,0 +1,20 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "implicit array to vector and vector to array" { + const S = struct { + fn doTheTest() void { + var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40}; + const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4}; + v +%= x; + const result: [4]i32 = v; + assertOrPanic(result[0] == 11); + assertOrPanic(result[1] == 22); + assertOrPanic(result[2] == 33); + assertOrPanic(result[3] == 44); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + From 06be65a602c2cd83bfdb9a1fa31e0ce038b0262d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Feb 2019 22:14:35 -0500 Subject: [PATCH 136/218] fix vector debug info tripping LLVM assertion --- src/analyze.cpp | 5 +++-- src/zig_llvm.cpp | 6 +++--- src/zig_llvm.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index ff961a7044..d92d337c69 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4486,8 +4486,9 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { buf_resize(&entry->name, 0); buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); - entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len, - LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type); + entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, + len * type_size_bits(g, elem_type), + LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type, len); g->type_table.put(type_id, entry); return entry; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 65f6b5abb7..e5a4890914 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -264,12 +264,12 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch } struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, - uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty) + uint64_t SizeInBits, uint32_t AlignInBits, struct ZigLLVMDIType *Ty, uint32_t elem_count) { SmallVector subrange; - subrange.push_back(reinterpret_cast(dibuilder)->getOrCreateSubrange(0, Size)); + subrange.push_back(reinterpret_cast(dibuilder)->getOrCreateSubrange(0, elem_count)); DIType *di_type = reinterpret_cast(dibuilder)->createVectorType( - Size, + SizeInBits, AlignInBits, reinterpret_cast(Ty), reinterpret_cast(dibuilder)->getOrCreateArray(subrange)); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 26dca1198b..b5b0e97b53 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -192,7 +192,7 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram); ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, - uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty); + uint64_t SizeInBits, uint32_t AlignInBits, struct ZigLLVMDIType *Ty, uint32_t elem_count); ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); From 4010f6a11dafa1d047d66a637a0efe58d80a52c6 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 5 Feb 2019 11:00:32 +0100 Subject: [PATCH 137/218] Added support for vector wrapping mult and sub * I also merged the code that generates ir for add, sub, and mult --- src/codegen.cpp | 122 +++++++++++++------------------- test/stage1/behavior/vector.zig | 17 ++--- 2 files changed, 58 insertions(+), 81 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index de2222afb7..226a137796 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast } +typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); + static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, IrInstructionBinOp *bin_op_instruction) { @@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, } else { zig_unreachable(); } + case IrBinOpMult: + case IrBinOpMultWrap: case IrBinOpAdd: case IrBinOpAddWrap: + case IrBinOpSub: + case IrBinOpSubWrap: { + // These are lookup table using the AddSubMul enum as the lookup. + // If AddSubMul ever changes, then these tables will be out of + // date. + static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; + static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; + static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; + static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; + + bool is_vector = type_entry->id == ZigTypeIdVector; + bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); + AddSubMul add_sub_mul = + op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : + op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : + AddSubMulMul; + + // The code that is generated for vectors and scalars are the same, + // so we can just set type_entry to the vectors elem_type an avoid + // a lot of repeated code. + if (is_vector) + type_entry = type_entry->data.vector.elem_type; + if (type_entry->id == ZigTypeIdPointer) { assert(type_entry->data.pointer.ptr_len == PtrLenUnknown); + LLVMValueRef subscript_value; + if (is_vector) + zig_panic("TODO: Implement vector operations on pointers."); + + switch (add_sub_mul) { + case AddSubMulAdd: + subscript_value = op2_value; + break; + case AddSubMulSub: + subscript_value = LLVMBuildNeg(g->builder, op2_value, ""); + break; + case AddSubMulMul: + zig_unreachable(); + } + // TODO runtime safety - return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, ""); + return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, ""); } else if (type_entry->id == ZigTypeIdFloat) { ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); + return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } else if (type_entry->id == ZigTypeIdInt) { - bool is_wrapping = (op_id == IrBinOpAddWrap); if (is_wrapping) { - return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); + return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } else if (want_runtime_safety) { - return gen_overflow_op(g, type_entry, AddSubMulAdd, op1_value, op2_value); + if (is_vector) + zig_panic("TODO: Implement runtime safety vector operations."); + return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value); } else if (type_entry->data.integral.is_signed) { - return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); + return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } else { - return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); - } - } else if (type_entry->id == ZigTypeIdVector) { - ZigType *elem_type = type_entry->data.vector.elem_type; - if (elem_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); - } else if (elem_type->id == ZigTypeIdPointer) { - zig_panic("TODO codegen for pointers in vectors"); - } else if (elem_type->id == ZigTypeIdInt) { - bool is_wrapping = (op_id == IrBinOpAddWrap); - if (is_wrapping) { - return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); - } else if (want_runtime_safety) { - zig_panic("TODO runtime safety for vector integer addition"); - } else if (elem_type->data.integral.is_signed) { - return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); - } else { - return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); + return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } } else { zig_unreachable(); } + } case IrBinOpBinOr: return LLVMBuildOr(g->builder, op1_value, op2_value, ""); case IrBinOpBinXor: @@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); } } - case IrBinOpSub: - case IrBinOpSubWrap: - if (type_entry->id == ZigTypeIdPointer) { - assert(type_entry->data.pointer.ptr_len == PtrLenUnknown); - // TODO runtime safety - LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, ""); - return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, ""); - } else if (type_entry->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return LLVMBuildFSub(g->builder, op1_value, op2_value, ""); - } else if (type_entry->id == ZigTypeIdInt) { - bool is_wrapping = (op_id == IrBinOpSubWrap); - if (is_wrapping) { - return LLVMBuildSub(g->builder, op1_value, op2_value, ""); - } else if (want_runtime_safety) { - return gen_overflow_op(g, type_entry, AddSubMulSub, op1_value, op2_value); - } else if (type_entry->data.integral.is_signed) { - return LLVMBuildNSWSub(g->builder, op1_value, op2_value, ""); - } else { - return LLVMBuildNUWSub(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpMult: - case IrBinOpMultWrap: - if (type_entry->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return LLVMBuildFMul(g->builder, op1_value, op2_value, ""); - } else if (type_entry->id == ZigTypeIdInt) { - bool is_wrapping = (op_id == IrBinOpMultWrap); - if (is_wrapping) { - return LLVMBuildMul(g->builder, op1_value, op2_value, ""); - } else if (want_runtime_safety) { - return gen_overflow_op(g, type_entry, AddSubMulMul, op1_value, op2_value); - } else if (type_entry->data.integral.is_signed) { - return LLVMBuildNSWMul(g->builder, op1_value, op2_value, ""); - } else { - return LLVMBuildNUWMul(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } case IrBinOpDivUnspecified: return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), op1_value, op2_value, type_entry, DivKindFloat); diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 53c5d01381..c97ee0e3d6 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -1,20 +1,17 @@ const std = @import("std"); +const mem = std.mem; const assertOrPanic = std.debug.assertOrPanic; -test "implicit array to vector and vector to array" { +test "vector wrap operators" { const S = struct { fn doTheTest() void { - var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40}; - const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4}; - v +%= x; - const result: [4]i32 = v; - assertOrPanic(result[0] == 11); - assertOrPanic(result[1] == 22); - assertOrPanic(result[2] == 33); - assertOrPanic(result[3] == 44); + const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; + const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; + assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); + assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); + assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); } }; S.doTheTest(); comptime S.doTheTest(); } - From ac4e38226b45081dfb66f006bba38b11c121ad45 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 5 Feb 2019 10:28:05 -0500 Subject: [PATCH 138/218] docs: clarify passing aggregate types as parameters --- doc/langref.html.in | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 144c8571c4..e3ba0e3956 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -3192,7 +3192,16 @@ fn foo() void { } {#code_end#} {#header_open|Pass-by-value Parameters#}

- In Zig, structs, unions, and enums with payloads can be passed directly to a function: + Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters + are copied, and then the copy is available in the function body. This is called "passing by value". + Copying a primitive type is essentially free and typically involves nothing more than + setting a register. +

+

+ Structs, unions, and arrays can sometimes be more efficiently passed as a reference, since a copy + could be arbitrarily expensive depending on the size. When these types are passed + as parameters, Zig may choose to copy and pass by value, or pass by reference, whichever way + Zig decides will be faster. This is made possible, in part, by the fact that parameters are immutable.

{#code_begin|test#} const Point = struct { @@ -3201,20 +3210,20 @@ const Point = struct { }; fn foo(point: Point) i32 { + // Here, `point` could be a reference, or a copy. The function body + // can ignore the difference and treat it as a value. Be very careful + // taking the address of the parameter - it should be treated as if + // the address will become invalid when the function returns. return point.x + point.y; } const assert = @import("std").debug.assert; -test "pass aggregate type by non-copy value to function" { +test "pass struct to function" { assert(foo(Point{ .x = 1, .y = 2 }) == 3); } {#code_end#}

- In this case, the value may be passed by reference, or by value, whichever way - Zig decides will be faster. -

-

For extern functions, Zig follows the C ABI for passing structs and unions by value.

{#header_close#} From 075fda3c732dc0e34d9917cc9c441b4dff75aa0e Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 5 Feb 2019 20:36:57 +0100 Subject: [PATCH 139/218] translate-c: add tests. Commented for now as the output is currently empty until #646 is fixed. --- test/translate_c.zig | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/translate_c.zig b/test/translate_c.zig index 13f2a964d0..02020ddd73 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1416,4 +1416,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ } \\} ); + + // cases.add("empty array with initializer", + // "int a[4] = {};" + // , + // "pub var a: [4]c_int = [1]c_int{0} ** 4;" + // ); + + // cases.add("array with initialization", + // "int a[4] = {1, 2, 3, 4};" + // , + // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};" + // ); + + // cases.add("array with incomplete initialization", + // "int a[4] = {3, 4};" + // , + // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);" + // ); + + // cases.add("2D array with initialization", + // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };" + // , + // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};" + // ); + + // cases.add("2D array with incomplete initialization", + // "int a[3][3] = { {1, 2}, {4, 5, 6} };" + // , + // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};" + // ); } From a9faace8b4c9b2bef9425c4cdb136ff8fec056b8 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 5 Feb 2019 22:44:14 +0100 Subject: [PATCH 140/218] Notify failure to create a process when the executable is not found even in PATH. --- std/os/child_process.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 7aa8582369..37f75483a6 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -610,6 +610,9 @@ pub const ChildProcess = struct { } else { return err; } + } else { + // Every other error would have been returned earlier. + return error.FileNotFound; } }; From 6860db66fed86de6cea57134c12374905abac8d8 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 5 Feb 2019 23:13:17 +0100 Subject: [PATCH 141/218] Typo: use the joined path to try executables available from PATH. --- std/os/child_process.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 37f75483a6..871f9dd701 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -600,7 +600,7 @@ pub const ChildProcess = struct { const joined_path = try os.path.join(self.allocator, search_path, app_name); defer self.allocator.free(joined_path); - const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name); + const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path); defer self.allocator.free(joined_path_w); if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { From 20e2d8da616aa6406572e64274fec0740cb626c6 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Wed, 6 Feb 2019 04:04:38 +0000 Subject: [PATCH 142/218] Fixed Serializer and BitOutStream when used with streams that have empty error sets. --- std/io.zig | 10 +++++----- std/io_test.zig | 11 ++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/std/io.zig b/std/io.zig index c8701aeda6..81d90def6e 100644 --- a/std/io.zig +++ b/std/io.zig @@ -912,7 +912,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { } /// Flush any remaining bits to the stream. - pub fn flushBits(self: *Self) !void { + pub fn flushBits(self: *Self) Error!void { if (self.bit_count == 0) return; try self.out_stream.writeByte(self.bit_buffer); self.bit_buffer = 0; @@ -1079,7 +1079,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E } //@BUG: inferred error issue. See: #1386 - fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { + fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T { comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); const u8_bit_count = 8; @@ -1287,11 +1287,11 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com } /// Flushes any unwritten bits to the stream - pub fn flush(self: *Self) Stream.Error!void { + pub fn flush(self: *Self) Error!void { if (is_packed) return self.out_stream.flushBits(); } - fn serializeInt(self: *Self, value: var) !void { + fn serializeInt(self: *Self, value: var) Error!void { const T = @typeOf(value); comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); @@ -1323,7 +1323,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com } /// Serializes the passed value into the stream - pub fn serialize(self: *Self, value: var) !void { + pub fn serialize(self: *Self, value: var) Error!void { const T = comptime @typeOf(value); if (comptime trait.isIndexable(T)) { diff --git a/std/io_test.zig b/std/io_test.zig index 0bee0ddaf0..9a0687ec69 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -357,6 +357,15 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); + + //Verify that empty error set works with serializer. + //deserializer is covered by SliceInStream + const NullError = io.NullOutStream.Error; + var null_out = io.NullOutStream.init(); + var null_out_stream = &null_out.stream; + var null_serializer = io.Serializer(endian, is_packed, NullError).init(null_out_stream); + try null_serializer.serialize(data_mem[0..]); + try null_serializer.flush(); } test "Serializer/Deserializer Int" { @@ -568,4 +577,4 @@ test "Deserializer bad data" { try testBadData(builtin.Endian.Little, false); try testBadData(builtin.Endian.Big, true); try testBadData(builtin.Endian.Little, true); -} \ No newline at end of file +} From 3abf293a84b4dc052c0d735018db520eade6274b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Feb 2019 11:52:36 -0500 Subject: [PATCH 143/218] doc/targets.md has moved to the github wiki https://github.com/ziglang/zig/wiki/How-to-Add-Support-For-More-Targets --- doc/targets.md | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 doc/targets.md diff --git a/doc/targets.md b/doc/targets.md deleted file mode 100644 index e5c6ab5534..0000000000 --- a/doc/targets.md +++ /dev/null @@ -1,15 +0,0 @@ -# How to Add Support For More Targets - -Create bootstrap code in std/bootstrap.zig and add conditional compilation -logic. This code is responsible for the real executable entry point, calling -main() and making the exit syscall when main returns. - -How to pass a byvalue struct parameter in the C calling convention is -target-specific. Add logic for how to do function prototypes and function calls -for the target when an exported or external function has a byvalue struct. - -Write the target-specific code in the standard library. - -Update the C integer types to be the correct size for the target. - -Make sure that `c_longdouble` codegens the correct floating point value. From b1775ca168e0bcfba6753346c5226881da49c6c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Feb 2019 13:48:04 -0500 Subject: [PATCH 144/218] thread local storage working for linux x86_64 --- CMakeLists.txt | 1 + src/all_types.hpp | 13 ++-- src/analyze.cpp | 69 +++++++++++++------- src/analyze.hpp | 1 + src/ast_render.cpp | 7 +- src/codegen.cpp | 7 ++ src/ir.cpp | 4 ++ src/parser.cpp | 22 ++++--- src/tokenizer.cpp | 2 + src/tokenizer.hpp | 1 + std/debug/index.zig | 1 - std/heap.zig | 7 +- std/index.zig | 3 +- std/mem.zig | 20 ++++++ std/os/index.zig | 119 +++++++++++++++++++--------------- std/os/startup.zig | 26 ++++++++ std/os/test.zig | 16 +++++ std/special/bootstrap.zig | 63 ++++++++++++++++-- test/compile_errors.zig | 19 ++++++ test/stage1/behavior/misc.zig | 8 +++ 20 files changed, 306 insertions(+), 103 deletions(-) create mode 100644 std/os/startup.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd6a1dcfa..a093bfbfd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,7 @@ set(ZIG_STD_FILES "os/linux/vdso.zig" "os/linux/x86_64.zig" "os/path.zig" + "os/startup.zig" "os/time.zig" "os/uefi.zig" "os/windows/advapi32.zig" diff --git a/src/all_types.hpp b/src/all_types.hpp index c4c9e13cfb..5af4e71157 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -544,12 +544,7 @@ struct AstNodeDefer { }; struct AstNodeVariableDeclaration { - VisibMod visib_mod; Buf *symbol; - bool is_const; - bool is_comptime; - bool is_export; - bool is_extern; // one or both of type and expr will be non null AstNode *type; AstNode *expr; @@ -559,6 +554,13 @@ struct AstNodeVariableDeclaration { AstNode *align_expr; // populated if the "section(S)" is present AstNode *section_expr; + Token *threadlocal_tok; + + VisibMod visib_mod; + bool is_const; + bool is_comptime; + bool is_export; + bool is_extern; }; struct AstNodeTestDecl { @@ -1873,6 +1875,7 @@ struct ZigVar { bool shadowable; bool src_is_const; bool gen_is_const; + bool is_thread_local; }; struct ErrorTableEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index ff961a7044..96f1faaaa9 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -28,28 +28,10 @@ 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); -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - if (node->owner->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, node->owner->c_import_node, - buf_sprintf("compiler bug: @cImport generated invalid zig code")); - - add_error_note(g, err, node, msg); - - g->errors.append(err); - return err; - } - - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); - - g->errors.append(err); - return err; -} - -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { - if (node->owner->c_import_node != nullptr) { +static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token, + Buf *msg) +{ + if (owner->c_import_node != nullptr) { // if this happens, then translate_c generated code that // failed semantic analysis, which isn't supposed to happen @@ -64,13 +46,46 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m return note; } - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); + ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column, + owner->source_code, owner->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) { + // 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, + buf_sprintf("compiler bug: @cImport generated invalid zig code")); + + add_error_note_token(g, err, owner, token, msg); + + 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); + + g->errors.append(err); + return err; +} + +ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { + Token fake_token; + fake_token.start_line = node->line; + fake_token.start_column = node->column; + return add_token_error(g, node->owner, &fake_token, msg); +} + +ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { + Token fake_token; + fake_token.start_line = node->line; + fake_token.start_column = node->column; + return add_error_note_token(g, parent_msg, node->owner, &fake_token, msg); +} + ZigType *new_type_table_entry(ZigTypeId id) { ZigType *entry = allocate(1); entry->id = id; @@ -3668,6 +3683,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { bool is_const = var_decl->is_const; bool is_extern = var_decl->is_extern; bool is_export = var_decl->is_export; + bool is_thread_local = var_decl->threadlocal_tok != nullptr; ZigType *explicit_type = nullptr; if (var_decl->type) { @@ -3727,6 +3743,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, is_const, init_val, &tld_var->base, type); tld_var->var->linkage = linkage; + tld_var->var->is_thread_local = is_thread_local; if (implicit_type != nullptr && type_is_invalid(implicit_type)) { tld_var->var->var_type = g->builtin_types.entry_invalid; @@ -3747,6 +3764,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } } + if (is_thread_local && is_const) { + add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant")); + } + g->global_vars.append(tld_var); } diff --git a/src/analyze.hpp b/src/analyze.hpp index f558fa44b0..9773782510 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -12,6 +12,7 @@ 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_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg); ZigType *new_type_table_entry(ZigTypeId id); ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 994ba5f5b1..34a7faa2a5 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -132,6 +132,10 @@ static const char *const_or_var_string(bool is_const) { return is_const ? "const" : "var"; } +static const char *thread_local_string(Token *tok) { + return (tok == nullptr) ? "" : "threadlocal "; +} + const char *container_string(ContainerKind kind) { switch (kind) { case ContainerKindEnum: return "enum"; @@ -554,8 +558,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { { const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod); const char *extern_str = extern_string(node->data.variable_declaration.is_extern); + const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok); const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const); - fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var); + fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var); print_symbol(ar, node->data.variable_declaration.symbol); if (node->data.variable_declaration.type) { diff --git a/src/codegen.cpp b/src/codegen.cpp index de2222afb7..d8fc077efc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6445,6 +6445,9 @@ static void do_code_gen(CodeGen *g) { maybe_import_dll(g, global_value, GlobalLinkageIdStrong); LLVMSetAlignment(global_value, var->align_bytes); LLVMSetGlobalConstant(global_value, var->gen_is_const); + if (var->is_thread_local && !g->is_single_threaded) { + LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); + } } } else { bool exported = (var->linkage == VarLinkageExport); @@ -6470,6 +6473,9 @@ static void do_code_gen(CodeGen *g) { } LLVMSetGlobalConstant(global_value, var->gen_is_const); + if (var->is_thread_local && !g->is_single_threaded) { + LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); + } } var->value_ref = global_value; @@ -7520,6 +7526,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename); 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); diff --git a/src/ir.cpp b/src/ir.cpp index 3cbbdc8103..02b2b12230 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5204,6 +5204,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod add_node_error(irb->codegen, variable_declaration->section_expr, buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); } + if (variable_declaration->threadlocal_tok != nullptr) { + add_token_error(irb->codegen, node->owner, variable_declaration->threadlocal_tok, + buf_sprintf("function-local variable '%s' cannot be threadlocal", buf_ptr(variable_declaration->symbol))); + } // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. diff --git a/src/parser.cpp b/src/parser.cpp index 81bd469d1c..1c1af87c51 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -844,12 +844,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON static AstNode *ast_parse_var_decl(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordConst); - if (first == nullptr) - first = eat_token_if(pc, TokenIdKeywordVar); - if (first == nullptr) - return nullptr; - + Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); + Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); + if (mut_kw == nullptr) + mut_kw = eat_token_if(pc, TokenIdKeywordVar); + if (mut_kw == nullptr) { + if (thread_local_kw == nullptr) { + return nullptr; + } else { + ast_invalid_token_error(pc, peek_token(pc)); + } + } Token *identifier = expect_token(pc, TokenIdSymbol); AstNode *type_expr = nullptr; if (eat_token_if(pc, TokenIdColon) != nullptr) @@ -863,8 +868,9 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { expect_token(pc, TokenIdSemicolon); - AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, first); - res->data.variable_declaration.is_const = first->id == TokenIdKeywordConst; + AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); + res->data.variable_declaration.threadlocal_tok = thread_local_kw; + res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; res->data.variable_declaration.symbol = token_buf(identifier); res->data.variable_declaration.type = type_expr; res->data.variable_declaration.align_expr = align_expr; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d43bfabf6d..3acd605748 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -146,6 +146,7 @@ static const struct ZigKeyword zig_keywords[] = { {"suspend", TokenIdKeywordSuspend}, {"switch", TokenIdKeywordSwitch}, {"test", TokenIdKeywordTest}, + {"threadlocal", TokenIdKeywordThreadLocal}, {"true", TokenIdKeywordTrue}, {"try", TokenIdKeywordTry}, {"undefined", TokenIdKeywordUndefined}, @@ -1586,6 +1587,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordSwitch: return "switch"; case TokenIdKeywordTest: return "test"; + case TokenIdKeywordThreadLocal: return "threadlocal"; case TokenIdKeywordTrue: return "true"; case TokenIdKeywordTry: return "try"; case TokenIdKeywordUndefined: return "undefined"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 1574e95571..17f36699b3 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -88,6 +88,7 @@ enum TokenId { TokenIdKeywordSuspend, TokenIdKeywordSwitch, TokenIdKeywordTest, + TokenIdKeywordThreadLocal, TokenIdKeywordTrue, TokenIdKeywordTry, TokenIdKeywordUndefined, diff --git a/std/debug/index.zig b/std/debug/index.zig index 838bd0c166..b4ef849509 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -37,7 +37,6 @@ const Module = struct { var stderr_file: os.File = undefined; var stderr_file_out_stream: os.File.OutStream = undefined; -/// TODO multithreaded awareness var stderr_stream: ?*io.OutStream(os.File.WriteError) = null; var stderr_mutex = std.Mutex.init(); pub fn warn(comptime fmt: []const u8, args: ...) void { diff --git a/std/heap.zig b/std/heap.zig index fd2ce1e965..1403f8e831 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -106,9 +106,7 @@ pub const DirectAllocator = struct { }; const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory; const root_addr = @ptrToInt(ptr); - const rem = @rem(root_addr, alignment); - const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); - const adjusted_addr = root_addr + march_forward_bytes; + const adjusted_addr = mem.alignForward(root_addr, alignment); const record_addr = adjusted_addr + n; @intToPtr(*align(1) usize, record_addr).* = root_addr; return @intToPtr([*]u8, adjusted_addr)[0..n]; @@ -126,8 +124,7 @@ pub const DirectAllocator = struct { const base_addr = @ptrToInt(old_mem.ptr); const old_addr_end = base_addr + old_mem.len; const new_addr_end = base_addr + new_size; - const rem = @rem(new_addr_end, os.page_size); - const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem); + const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size); if (old_addr_end > new_addr_end_rounded) { _ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded); } diff --git a/std/index.zig b/std/index.zig index 80d1e46bb6..ef3988460f 100644 --- a/std/index.zig +++ b/std/index.zig @@ -33,8 +33,8 @@ pub const io = @import("io.zig"); pub const json = @import("json.zig"); pub const macho = @import("macho.zig"); pub const math = @import("math/index.zig"); -pub const meta = @import("meta/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"); @@ -45,6 +45,7 @@ pub const unicode = @import("unicode.zig"); pub const zig = @import("zig/index.zig"); pub const lazyInit = @import("lazy_init.zig").lazyInit; +pub const startup = @import("os/startup.zig"); test "std" { // run tests from these diff --git a/std/mem.zig b/std/mem.zig index 26ae4ef089..178a5f6c6f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -1366,3 +1366,23 @@ test "std.mem.subArrayPtr" { sub2[1] = 'X'; debug.assert(std.mem.eql(u8, a2, "abcXef")); } + +/// Round an address up to the nearest aligned address +pub fn alignForward(addr: usize, alignment: usize) usize { + return (addr + alignment - 1) & ~(alignment - 1); +} + +test "std.mem.alignForward" { + debug.assertOrPanic(alignForward(1, 1) == 1); + debug.assertOrPanic(alignForward(2, 1) == 2); + debug.assertOrPanic(alignForward(1, 2) == 2); + debug.assertOrPanic(alignForward(2, 2) == 2); + debug.assertOrPanic(alignForward(3, 2) == 4); + debug.assertOrPanic(alignForward(4, 2) == 4); + debug.assertOrPanic(alignForward(7, 8) == 8); + debug.assertOrPanic(alignForward(8, 8) == 8); + debug.assertOrPanic(alignForward(9, 8) == 16); + debug.assertOrPanic(alignForward(15, 8) == 16); + debug.assertOrPanic(alignForward(16, 8) == 16); + debug.assertOrPanic(alignForward(17, 8) == 24); +} diff --git a/std/os/index.zig b/std/os/index.zig index 451c0a3436..68b3409757 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -8,6 +8,9 @@ const is_posix = switch (builtin.os) { }; const os = @This(); +// See the comment in startup.zig for why this does not use the `std` global above. +const startup = @import("std").startup; + test "std.os" { _ = @import("child_process.zig"); _ = @import("darwin.zig"); @@ -667,14 +670,11 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { } } -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| { + } else if (startup.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) @@ -692,12 +692,7 @@ pub fn getBaseAddress() usize { return base; } const phdr = linuxGetAuxVal(std.elf.AT_PHDR); - const ElfHeader = switch (@sizeOf(usize)) { - 4 => std.elf.Elf32_Ehdr, - 8 => std.elf.Elf64_Ehdr, - else => @compileError("Unsupported architecture"), - }; - return phdr - @sizeOf(ElfHeader); + return phdr - @sizeOf(std.elf.Ehdr); }, builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header), builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), @@ -739,7 +734,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { try result.setMove(key, value); } } else { - for (posix_environ_raw) |ptr| { + for (startup.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]; @@ -761,7 +756,7 @@ test "os.getEnvMap" { /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { - for (posix_environ_raw) |ptr| { + for (startup.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]; @@ -1942,14 +1937,14 @@ pub const ArgIteratorPosix = struct { pub fn init() ArgIteratorPosix { return ArgIteratorPosix{ .index = 0, - .count = raw.len, + .count = startup.posix_argv_raw.len, }; } pub fn next(self: *ArgIteratorPosix) ?[]const u8 { if (self.index == self.count) return null; - const s = raw[self.index]; + const s = startup.posix_argv_raw[self.index]; self.index += 1; return cstr.toSlice(s); } @@ -1960,10 +1955,6 @@ pub const ArgIteratorPosix = struct { 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 { @@ -2908,14 +2899,15 @@ pub const Thread = struct { pub const Data = if (use_pthreads) struct { handle: Thread.Handle, - stack_addr: usize, - stack_len: usize, + mmap_addr: usize, + mmap_len: usize, } else switch (builtin.os) { builtin.Os.linux => struct { handle: Thread.Handle, - stack_addr: usize, - stack_len: usize, + mmap_addr: usize, + mmap_len: usize, + tls_end_addr: usize, }, builtin.Os.windows => struct { handle: Thread.Handle, @@ -2955,7 +2947,7 @@ pub const Thread = struct { posix.EDEADLK => unreachable, else => unreachable, } - assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0); } else switch (builtin.os) { builtin.Os.linux => { while (true) { @@ -2969,7 +2961,7 @@ pub const Thread = struct { else => unreachable, } } - assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + 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); @@ -3097,42 +3089,56 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0; - const mmap_len = default_stack_size; - const stack_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); - if (stack_addr == posix.MAP_FAILED) return error.OutOfMemory; - errdefer assert(posix.munmap(stack_addr, mmap_len) == 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 (startup.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 stack_end: usize = stack_addr + mmap_len; var arg: usize = undefined; if (@sizeOf(Context) != 0) { - stack_end -= @sizeOf(Context); - stack_end -= stack_end % @alignOf(Context); - assert(stack_end >= stack_addr); - const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, stack_end)); + arg = mmap_addr + context_start_offset; + const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg)); context_ptr.* = context; - arg = stack_end; } - stack_end -= @sizeOf(Thread); - stack_end -= stack_end % @alignOf(Thread); - assert(stack_end >= stack_addr); - const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, stack_end)); - - thread_ptr.data.stack_addr = stack_addr; - thread_ptr.data.stack_len = mmap_len; - - if (builtin.os == builtin.Os.windows) { - // use windows API directly - @compileError("TODO support spawnThread for Windows"); - } else if (Thread.use_pthreads) { + 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); - // align to page - stack_end -= stack_end % os.page_size; - assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 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) { @@ -3143,10 +3149,17 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread else => return unexpectedErrorPosix(@intCast(usize, err)), } } else if (builtin.os == builtin.Os.linux) { - // use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly - const flags = 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; - const newtls: usize = 0; - const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); + 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 (startup.linux_tls_phdr) |tls_phdr| { + @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), startup.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, diff --git a/std/os/startup.zig b/std/os/startup.zig new file mode 100644 index 0000000000..c54d274c5d --- /dev/null +++ b/std/os/startup.zig @@ -0,0 +1,26 @@ +// This file contains global variables that are initialized on startup from +// std/special/bootstrap.zig. There are a few things to be aware of here. +// +// First, when building an object or library, and no entry point is defined +// (such as pub fn main), std/special/bootstrap.zig is not included in the +// compilation. And so these global variables will remain set to the values +// you see here. +// +// Second, when using `zig test` to test the standard library, note that +// `zig test` is self-hosted. This means that it uses std/special/bootstrap.zig +// and an @import("std") from the install directory, which is distinct from +// the standard library files that we are directly testing with `zig test`. +// This means that these global variables would not get set. So the workaround +// here is that references to these globals from the standard library must +// use `@import("std").startup` rather than +// `@import("path/to/std/index.zig").startup` (and rather than the file path of +// this file directly). We also put "std" as a reference to itself in the +// standard library package so that this can work. + +const std = @import("../index.zig"); + +pub var linux_tls_phdr: ?*std.elf.Phdr = null; +pub var linux_tls_img_src: [*]const u8 = undefined; // defined when linux_tls_phdr is non-null +pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; +pub var posix_environ_raw: [][*]u8 = undefined; +pub var posix_argv_raw: [][*]u8 = undefined; diff --git a/std/os/test.zig b/std/os/test.zig index f14cf47786..bd9148d1b1 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -105,3 +105,19 @@ test "AtomicFile" { try os.deleteFile(test_out_file); } + +test "thread local storage" { + if (builtin.single_threaded) return error.SkipZigTest; + const thread1 = try std.os.spawnThread({}, testTls); + const thread2 = try std.os.spawnThread({}, testTls); + testTls({}); + thread1.wait(); + thread2.wait(); +} + +threadlocal var x: i32 = 1234; +fn testTls(context: void) void { + if (x != 1234) @panic("bad start value"); + x += 1; + if (x != 1235) @panic("bad end value"); +} diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 129bde913f..0e84f67481 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -4,6 +4,7 @@ const root = @import("@root"); const std = @import("std"); const builtin = @import("builtin"); +const assert = std.debug.assert; var argc_ptr: [*]usize = undefined; @@ -61,9 +62,23 @@ fn posixCallMainAndExit() noreturn { while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; if (builtin.os == builtin.Os.linux) { - const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1); - std.os.linux_elf_aux_maybe = @ptrCast([*]std.elf.Auxv, auxv); - std.debug.assert(std.os.linuxGetAuxVal(std.elf.AT_PAGESZ) == std.os.page_size); + // Scan auxiliary vector. + const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + std.startup.linux_elf_aux_maybe = auxv; + var i: usize = 0; + var at_phdr: usize = 0; + var at_phnum: usize = 0; + var at_phent: usize = 0; + while (auxv[i].a_un.a_val != 0) : (i += 1) { + switch (auxv[i].a_type) { + std.elf.AT_PAGESZ => assert(auxv[i].a_un.a_val == std.os.page_size), + std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, + std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, + std.elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, + else => {}, + } + } + if (!builtin.single_threaded) linuxInitializeThreadLocalStorage(at_phdr, at_phnum, at_phent); } std.os.posix.exit(callMainWithArgs(argc, argv, envp)); @@ -72,8 +87,8 @@ fn posixCallMainAndExit() noreturn { // This is marked inline because for some reason LLVM in release mode fails to inline it, // and we want fewer call frames in stack traces. inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { - std.os.ArgIteratorPosix.raw = argv[0..argc]; - std.os.posix_environ_raw = envp; + std.startup.posix_argv_raw = argv[0..argc]; + std.startup.posix_environ_raw = envp; return callMain(); } @@ -116,3 +131,41 @@ inline fn callMain() u8 { else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), } } + +var tls_end_addr: usize = undefined; +const main_thread_tls_align = 32; +var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; + +fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent: usize) void { + var phdr_addr = at_phdr; + var n = at_phnum; + var base: usize = 0; + while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) { + const phdr = @intToPtr(*std.elf.Phdr, phdr_addr); + // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917 + switch (phdr.p_type) { + std.elf.PT_PHDR => base = at_phdr - phdr.p_vaddr, + std.elf.PT_TLS => std.startup.linux_tls_phdr = phdr, + else => continue, + } + } + const tls_phdr = std.startup.linux_tls_phdr orelse return; + std.startup.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr); + assert(main_thread_tls_bytes.len >= tls_phdr.p_memsz); // not enough preallocated Thread Local Storage + assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough + @memcpy(&main_thread_tls_bytes, std.startup.linux_tls_img_src, tls_phdr.p_filesz); + tls_end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz; + linuxSetThreadArea(@ptrToInt(&tls_end_addr)); +} + +fn linuxSetThreadArea(addr: usize) void { + switch (builtin.arch) { + builtin.Arch.x86_64 => { + const ARCH_SET_FS = 0x1002; + const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, ARCH_SET_FS, addr); + // acrh_prctl is documented to never fail + assert(rc == 0); + }, + else => @compileError("Unsupported architecture"), + } +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 30d9ca5d70..acd1eada06 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,25 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "threadlocal qualifier on const", + \\threadlocal const x: i32 = 1234; + \\export fn entry() i32 { + \\ return x; + \\} + , + ".tmp_source.zig:1:13: error: threadlocal variable cannot be constant", + ); + + cases.add( + "threadlocal qualifier on local variable", + \\export fn entry() void { + \\ threadlocal var x: i32 = 1234; + \\} + , + ".tmp_source.zig:2:5: error: function-local variable 'x' cannot be threadlocal", + ); + cases.add( "@bitCast same size but bit count mismatch", \\export fn entry(byte: u8) void { diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 8d2555dddd..3cc8e5f31e 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -685,3 +685,11 @@ test "fn call returning scalar optional in equality expression" { fn getNull() ?*i32 { return null; } + +test "thread local variable" { + const S = struct { + threadlocal var t: i32 = 1234; + }; + S.t += 1; + assertOrPanic(S.t == 1235); +} From d2602b442e7cdea2e74584f9529917d7a53625fd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Feb 2019 14:32:20 -0500 Subject: [PATCH 145/218] require running std lib tests coherently this should actually improve CI times a bit too See the description at the top of std/os/startup.zig (deleted in this commit) for a more detailed understanding of what this commit does. --- CMakeLists.txt | 1 - src/codegen.cpp | 18 +++++++++++++----- src/codegen.hpp | 2 +- src/link.cpp | 2 +- src/main.cpp | 12 +++++++++--- std/build.zig | 10 ++++++++++ std/index.zig | 1 - std/os/index.zig | 31 +++++++++++++++++++++---------- std/os/startup.zig | 26 -------------------------- std/special/bootstrap.zig | 14 +++++++------- test/tests.zig | 3 +++ 11 files changed, 65 insertions(+), 55 deletions(-) delete mode 100644 std/os/startup.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index a093bfbfd9..4dd6a1dcfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,7 +587,6 @@ set(ZIG_STD_FILES "os/linux/vdso.zig" "os/linux/x86_64.zig" "os/path.zig" - "os/startup.zig" "os/time.zig" "os/uefi.zig" "os/windows/advapi32.zig" diff --git a/src/codegen.cpp b/src/codegen.cpp index d8fc077efc..5e282160d6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -88,7 +88,7 @@ static const char *symbols_that_llvm_depends_on[] = { }; CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir) + Buf *zig_lib_dir, Buf *override_std_dir) { CodeGen *g = allocate(1); @@ -96,8 +96,12 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out g->zig_lib_dir = zig_lib_dir; - g->zig_std_dir = buf_alloc(); - os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); + if (override_std_dir == nullptr) { + g->zig_std_dir = buf_alloc(); + os_path_join(zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); + } else { + g->zig_std_dir = override_std_dir; + } g->zig_c_headers_dir = buf_alloc(); os_path_join(zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); @@ -8356,8 +8360,12 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) { if (!entry) break; - cache_buf(ch, entry->key); - add_cache_pkg(g, ch, entry->value); + // TODO: I think we need a more sophisticated detection of + // packages we have already seen + if (entry->value != pkg) { + cache_buf(ch, entry->key); + add_cache_pkg(g, ch, entry->value); + } } } diff --git a/src/codegen.hpp b/src/codegen.hpp index 6f1cdfb677..4bd8f2dcca 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -15,7 +15,7 @@ #include CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir); + Buf *zig_lib_dir, Buf *override_std_dir); 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); diff --git a/src/link.cpp b/src/link.cpp index 593f7f309f..58221a99ea 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -42,7 +42,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) } CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type, - parent_gen->build_mode, parent_gen->zig_lib_dir); + parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir); child_gen->out_h_path = nullptr; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; diff --git a/src/main.cpp b/src/main.cpp index 81f49089be..73a1d75d42 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,6 +74,7 @@ static int print_full_usage(const char *arg0) { " -dirafter [dir] same as -isystem but do it last\n" " -isystem [dir] add additional search path for other .h files\n" " -mllvm [arg] forward an arg to LLVM's option processing\n" + " --override-std-dir [arg] use an alternate Zig standard library\n" "\n" "Link Options:\n" " --dynamic-linker [path] set the path to ld.so\n" @@ -395,6 +396,7 @@ int main(int argc, char **argv) { bool system_linker_hack = false; TargetSubsystem subsystem = TargetSubsystemAuto; bool is_single_threaded = false; + Buf *override_std_dir = nullptr; if (argc >= 2 && strcmp(argv[1], "build") == 0) { Buf zig_exe_path_buf = BUF_INIT; @@ -430,7 +432,8 @@ int main(int argc, char **argv) { Buf *build_runner_path = buf_alloc(); os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path); - CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir()); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(), + override_std_dir); g->enable_time_report = timing_info; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_create_from_str("build")); @@ -645,6 +648,8 @@ int main(int argc, char **argv) { clang_argv.append(argv[i]); 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, "--library-path") == 0 || strcmp(arg, "-L") == 0) { lib_dirs.append(argv[i]); } else if (strcmp(arg, "--library") == 0) { @@ -819,7 +824,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { - CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir); g->is_single_threaded = is_single_threaded; Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { @@ -878,7 +883,8 @@ int main(int argc, char **argv) { if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); + CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(), + override_std_dir); g->subsystem = subsystem; if (disable_pic) { diff --git a/std/build.zig b/std/build.zig index 5246d97339..07efcec30d 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1686,6 +1686,7 @@ pub const TestStep = struct { no_rosegment: bool, output_path: ?[]const u8, system_linker_hack: bool, + override_std_dir: ?[]const u8, pub fn init(builder: *Builder, root_src: []const u8) TestStep { const step_name = builder.fmt("test {}", root_src); @@ -1707,6 +1708,7 @@ pub const TestStep = struct { .no_rosegment = false, .output_path = null, .system_linker_hack = false, + .override_std_dir = null, }; } @@ -1737,6 +1739,10 @@ pub const TestStep = struct { self.build_mode = mode; } + pub fn overrideStdDir(self: *TestStep, dir_path: []const u8) void { + self.override_std_dir = dir_path; + } + pub fn setOutputPath(self: *TestStep, file_path: []const u8) void { self.output_path = file_path; @@ -1914,6 +1920,10 @@ pub const TestStep = struct { if (self.system_linker_hack) { try zig_args.append("--system-linker-hack"); } + if (self.override_std_dir) |dir| { + try zig_args.append("--override-std-dir"); + try zig_args.append(builder.pathFromRoot(dir)); + } try builder.spawnChild(zig_args.toSliceConst()); } diff --git a/std/index.zig b/std/index.zig index ef3988460f..2a63244004 100644 --- a/std/index.zig +++ b/std/index.zig @@ -45,7 +45,6 @@ pub const unicode = @import("unicode.zig"); pub const zig = @import("zig/index.zig"); pub const lazyInit = @import("lazy_init.zig").lazyInit; -pub const startup = @import("os/startup.zig"); test "std" { // run tests from these diff --git a/std/os/index.zig b/std/os/index.zig index 68b3409757..d17b6f4f40 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -8,8 +8,9 @@ const is_posix = switch (builtin.os) { }; const os = @This(); -// See the comment in startup.zig for why this does not use the `std` global above. -const startup = @import("std").startup; +comptime { + assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir +} test "std.os" { _ = @import("child_process.zig"); @@ -670,11 +671,14 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { } } +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 (startup.linux_elf_aux_maybe) |auxv| { + } 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) @@ -734,7 +738,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { try result.setMove(key, value); } } else { - for (startup.posix_environ_raw) |ptr| { + 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]; @@ -756,7 +760,7 @@ test "os.getEnvMap" { /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { - for (startup.posix_environ_raw) |ptr| { + 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]; @@ -1937,14 +1941,14 @@ pub const ArgIteratorPosix = struct { pub fn init() ArgIteratorPosix { return ArgIteratorPosix{ .index = 0, - .count = startup.posix_argv_raw.len, + .count = raw.len, }; } pub fn next(self: *ArgIteratorPosix) ?[]const u8 { if (self.index == self.count) return null; - const s = startup.posix_argv_raw[self.index]; + const s = raw[self.index]; self.index += 1; return cstr.toSlice(s); } @@ -1955,6 +1959,10 @@ pub const ArgIteratorPosix = struct { 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 { @@ -3000,6 +3008,9 @@ pub const SpawnThreadError = error{ 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 @@ -3109,7 +3120,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread } // Finally, the Thread Local Storage, if any. if (!Thread.use_pthreads) { - if (startup.linux_tls_phdr) |tls_phdr| { + if (linux_tls_phdr) |tls_phdr| { l = mem.alignForward(l, tls_phdr.p_align); tls_start_offset = l; l += tls_phdr.p_memsz; @@ -3153,8 +3164,8 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED; var newtls: usize = undefined; - if (startup.linux_tls_phdr) |tls_phdr| { - @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), startup.linux_tls_img_src, tls_phdr.p_filesz); + 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; diff --git a/std/os/startup.zig b/std/os/startup.zig deleted file mode 100644 index c54d274c5d..0000000000 --- a/std/os/startup.zig +++ /dev/null @@ -1,26 +0,0 @@ -// This file contains global variables that are initialized on startup from -// std/special/bootstrap.zig. There are a few things to be aware of here. -// -// First, when building an object or library, and no entry point is defined -// (such as pub fn main), std/special/bootstrap.zig is not included in the -// compilation. And so these global variables will remain set to the values -// you see here. -// -// Second, when using `zig test` to test the standard library, note that -// `zig test` is self-hosted. This means that it uses std/special/bootstrap.zig -// and an @import("std") from the install directory, which is distinct from -// the standard library files that we are directly testing with `zig test`. -// This means that these global variables would not get set. So the workaround -// here is that references to these globals from the standard library must -// use `@import("std").startup` rather than -// `@import("path/to/std/index.zig").startup` (and rather than the file path of -// this file directly). We also put "std" as a reference to itself in the -// standard library package so that this can work. - -const std = @import("../index.zig"); - -pub var linux_tls_phdr: ?*std.elf.Phdr = null; -pub var linux_tls_img_src: [*]const u8 = undefined; // defined when linux_tls_phdr is non-null -pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; -pub var posix_environ_raw: [][*]u8 = undefined; -pub var posix_argv_raw: [][*]u8 = undefined; diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 0e84f67481..97699e0cc5 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -64,7 +64,7 @@ fn posixCallMainAndExit() noreturn { if (builtin.os == builtin.Os.linux) { // Scan auxiliary vector. const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); - std.startup.linux_elf_aux_maybe = auxv; + std.os.linux_elf_aux_maybe = auxv; var i: usize = 0; var at_phdr: usize = 0; var at_phnum: usize = 0; @@ -87,8 +87,8 @@ fn posixCallMainAndExit() noreturn { // This is marked inline because for some reason LLVM in release mode fails to inline it, // and we want fewer call frames in stack traces. inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { - std.startup.posix_argv_raw = argv[0..argc]; - std.startup.posix_environ_raw = envp; + std.os.ArgIteratorPosix.raw = argv[0..argc]; + std.os.posix_environ_raw = envp; return callMain(); } @@ -145,15 +145,15 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent: // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917 switch (phdr.p_type) { std.elf.PT_PHDR => base = at_phdr - phdr.p_vaddr, - std.elf.PT_TLS => std.startup.linux_tls_phdr = phdr, + std.elf.PT_TLS => std.os.linux_tls_phdr = phdr, else => continue, } } - const tls_phdr = std.startup.linux_tls_phdr orelse return; - std.startup.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr); + const tls_phdr = std.os.linux_tls_phdr orelse return; + std.os.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr); assert(main_thread_tls_bytes.len >= tls_phdr.p_memsz); // not enough preallocated Thread Local Storage assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough - @memcpy(&main_thread_tls_bytes, std.startup.linux_tls_img_src, tls_phdr.p_filesz); + @memcpy(&main_thread_tls_bytes, std.os.linux_tls_img_src, tls_phdr.p_filesz); tls_end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz; linuxSetThreadArea(@ptrToInt(&tls_end_addr)); } diff --git a/test/tests.zig b/test/tests.zig index 548496fa2f..fc188f5550 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -194,6 +194,9 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons if (link_libc) { these_tests.linkSystemLibrary("c"); } + if (mem.eql(u8, name, "std")) { + these_tests.overrideStdDir("std"); + } step.dependOn(&these_tests.step); } } From 89ffb5819703c81514e4f29d2cadb5b74ea1f840 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Feb 2019 18:32:41 -0500 Subject: [PATCH 146/218] implement Thread Local Storage on Windows --- CMakeLists.txt | 1 + src/codegen.cpp | 14 ++++++++------ std/os/windows/index.zig | 19 ++++++++++++++++++- std/os/windows/kernel32.zig | 4 ++++ std/os/windows/tls.zig | 36 ++++++++++++++++++++++++++++++++++++ std/special/bootstrap.zig | 4 +++- 6 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 std/os/windows/tls.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd6a1dcfa..d6bd8a6c2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -596,6 +596,7 @@ set(ZIG_STD_FILES "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" diff --git a/src/codegen.cpp b/src/codegen.cpp index 5e282160d6..7169669426 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6365,6 +6365,12 @@ static void validate_inline_fns(CodeGen *g) { report_errors_and_maybe_exit(g); } +static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { + if (var->is_thread_local && !g->is_single_threaded) { + LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); + } +} + static void do_code_gen(CodeGen *g) { assert(!g->errors.length); @@ -6449,9 +6455,7 @@ static void do_code_gen(CodeGen *g) { maybe_import_dll(g, global_value, GlobalLinkageIdStrong); LLVMSetAlignment(global_value, var->align_bytes); LLVMSetGlobalConstant(global_value, var->gen_is_const); - if (var->is_thread_local && !g->is_single_threaded) { - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } + set_global_tls(g, var, global_value); } } else { bool exported = (var->linkage == VarLinkageExport); @@ -6477,9 +6481,7 @@ static void do_code_gen(CodeGen *g) { } LLVMSetGlobalConstant(global_value, var->gen_is_const); - if (var->is_thread_local && !g->is_single_threaded) { - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } + set_global_tls(g, var, global_value); } var->value_ref = global_value; diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 3f19905835..8e9ed8b8db 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -49,7 +49,10 @@ pub const UNICODE = false; pub const WCHAR = u16; pub const WORD = u16; pub const LARGE_INTEGER = i64; -pub const LONG = c_long; +pub const ULONG = u32; +pub const LONG = i32; +pub const ULONGLONG = u64; +pub const LONGLONG = i64; pub const TRUE = 1; pub const FALSE = 0; @@ -380,3 +383,17 @@ pub const COORD = extern struct { }; 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 66b9552c5f..ce8443de02 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -164,6 +164,10 @@ pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void; pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL; +pub extern "kernel32" stdcallcc fn TlsAlloc() DWORD; + +pub extern "kernel32" stdcallcc fn TlsFree(dwTlsIndex: DWORD) BOOL; + pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD; pub extern "kernel32" stdcallcc fn WriteFile( diff --git a/std/os/windows/tls.zig b/std/os/windows/tls.zig new file mode 100644 index 0000000000..9e62a7c5c6 --- /dev/null +++ b/std/os/windows/tls.zig @@ -0,0 +1,36 @@ +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/special/bootstrap.zig b/std/special/bootstrap.zig index 97699e0cc5..6dcc90b372 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -45,7 +45,9 @@ nakedcc fn _start() noreturn { extern fn WinMainCRTStartup() noreturn { @setAlignStack(16); - + if (!builtin.single_threaded) { + _ = @import("../os/windows/tls.zig"); + } std.os.windows.ExitProcess(callMain()); } From 36bade5c562bf0b2479b6dfdd465a1a312890835 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 00:42:41 -0500 Subject: [PATCH 147/218] fixups, and modify std.mem.join and std.os.path.resolve API * zig fmt * std.mem.join takes a slice of slices instead of var args * std.mem.join takes a separator slice rather than byte, and always inserts it. Previously it would not insert the separator if there already was one, violating the documented behavior. * std.mem.join calculates exactly the correct amount to allocate and has no call to allocator.shrink() * bring back joinWindows and joinPosix and the corresponding tests. it is intended to be able to call these functions from any OS. * rename std.os.path.resolveSlice to resolve (now resolve takes a slice of slices instead of var args) --- build.zig | 35 ++++-- doc/docgen.zig | 25 ++++- src-self-hosted/libc_installation.zig | 15 ++- std/build.zig | 79 +++++++++---- std/debug/index.zig | 4 +- std/event/fs.zig | 4 +- std/mem.zig | 49 ++++----- std/os/child_process.zig | 2 +- std/os/get_app_data_dir.zig | 7 +- std/os/index.zig | 7 +- std/os/path.zig | 152 ++++++++++++++++---------- test/cli.zig | 2 +- test/tests.zig | 55 ++++++++-- 13 files changed, 290 insertions(+), 146 deletions(-) diff --git a/build.zig b/build.zig index b90f58ff51..5c7c5b8a18 100644 --- a/build.zig +++ b/build.zig @@ -16,7 +16,10 @@ pub fn build(b: *Builder) !void { var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe); - const langref_out_path = os.path.join(b.allocator, [][]const u8{ b.cache_root, "langref.html" }) catch unreachable; + const langref_out_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, "langref.html" }, + ) catch unreachable; var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{ docgen_exe.getOutputPath(), rel_zig_exe, @@ -125,13 +128,19 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { for (dep.libdirs.toSliceConst()) |lib_dir| { lib_exe_obj.addLibPath(lib_dir); } - const lib_dir = os.path.join(b.allocator, [][]const u8{dep.prefix, "lib"}) catch unreachable; + const lib_dir = os.path.join( + b.allocator, + [][]const u8{ dep.prefix, "lib" }, + ) catch unreachable; for (dep.system_libs.toSliceConst()) |lib| { const static_bare_name = if (mem.eql(u8, lib, "curses")) ([]const u8)("libncurses.a") else b.fmt("lib{}.a", lib); - const static_lib_name = os.path.join(b.allocator, [][]const u8{lib_dir, static_bare_name}) catch unreachable; + const static_lib_name = os.path.join( + b.allocator, + [][]const u8{ lib_dir, static_bare_name }, + ) catch unreachable; const have_static = fileExists(static_lib_name) catch unreachable; if (have_static) { lib_exe_obj.addObjectFile(static_lib_name); @@ -159,7 +168,11 @@ fn fileExists(filename: []const u8) !bool { fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void { const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib"; - lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{ cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()) }) catch unreachable); + lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{ + cmake_binary_dir, + "zig_cpp", + b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()), + }) catch unreachable); } const LibraryDep = struct { @@ -235,8 +248,11 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { var it = mem.tokenize(stdlib_files, ";"); while (it.next()) |stdlib_file| { - const src_path = os.path.join(b.allocator, [][]const u8{"std", stdlib_file}) catch unreachable; - const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "std", stdlib_file}) catch unreachable; + const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable; + const dest_path = os.path.join( + b.allocator, + [][]const u8{ "lib", "zig", "std", stdlib_file }, + ) catch unreachable; b.installFile(src_path, dest_path); } } @@ -244,8 +260,11 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { var it = mem.tokenize(c_header_files, ";"); while (it.next()) |c_header_file| { - const src_path = os.path.join(b.allocator, [][]const u8{"c_headers", c_header_file}) catch unreachable; - const dest_path = os.path.join(b.allocator, [][]const u8{"lib", "zig", "include", c_header_file}) catch unreachable; + const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable; + const dest_path = os.path.join( + b.allocator, + [][]const u8{ "lib", "zig", "include", c_header_file }, + ) catch unreachable; b.installFile(src_path, dest_path); } } diff --git a/doc/docgen.zig b/doc/docgen.zig index 8b2a7e4c10..14e4700553 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -990,13 +990,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var try tokenizeAndPrint(tokenizer, out, code.source_token); try out.write(""); const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name); - const tmp_source_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_ext }); + const tmp_source_file_name = try os.path.join( + allocator, + [][]const u8{ tmp_dir_name, name_plus_ext }, + ); try io.writeFile(tmp_source_file_name, trimmed_raw_source); switch (code.id) { Code.Id.Exe => |expected_outcome| { const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext); - const tmp_bin_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_bin_ext }); + const tmp_bin_file_name = try os.path.join( + allocator, + [][]const u8{ tmp_dir_name, name_plus_bin_ext }, + ); var build_args = std.ArrayList([]const u8).init(allocator); defer build_args.deinit(); try build_args.appendSlice([][]const u8{ @@ -1024,7 +1030,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } for (code.link_objects) |link_object| { const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext); - const full_path_object = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_with_ext }); + const full_path_object = try os.path.join( + allocator, + [][]const u8{ tmp_dir_name, name_with_ext }, + ); try build_args.append("--object"); try build_args.append(full_path_object); try out.print(" --object {}", name_with_ext); @@ -1216,12 +1225,18 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var }, Code.Id.Obj => |maybe_error_match| { const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext); - const tmp_obj_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_obj_ext }); + const tmp_obj_file_name = try os.path.join( + allocator, + [][]const u8{ tmp_dir_name, name_plus_obj_ext }, + ); var build_args = std.ArrayList([]const u8).init(allocator); defer build_args.deinit(); const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name); - const output_h_file_name = try os.path.join(allocator, [][]const u8{ tmp_dir_name, name_plus_h_ext }); + const output_h_file_name = try os.path.join( + allocator, + [][]const u8{ tmp_dir_name, name_plus_h_ext }, + ); try build_args.appendSlice([][]const u8{ zig_exe, diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index 682e10c361..edcb9dc579 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -254,7 +254,10 @@ pub const LibCInstallation = struct { const stream = &std.io.BufferOutStream.init(&result_buf).stream; try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version); - const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "stdlib.h" }); + const stdlib_path = try std.os.path.join( + loop.allocator, + [][]const u8{ result_buf.toSliceConst(), "stdlib.h" }, + ); defer loop.allocator.free(stdlib_path); if (try fileExists(stdlib_path)) { @@ -283,7 +286,10 @@ pub const LibCInstallation = struct { builtin.Arch.aarch64v8 => try stream.write("arm"), else => return error.UnsupportedArchitecture, } - const ucrt_lib_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" }); + const ucrt_lib_path = try std.os.path.join( + loop.allocator, + [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" }, + ); defer loop.allocator.free(ucrt_lib_path); if (try fileExists(ucrt_lib_path)) { self.lib_dir = result_buf.toOwnedSlice(); @@ -358,7 +364,10 @@ pub const LibCInstallation = struct { builtin.Arch.aarch64v8 => try stream.write("arm\\"), else => return error.UnsupportedArchitecture, } - const kernel32_path = try std.os.path.join(loop.allocator, [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" }); + const kernel32_path = try std.os.path.join( + loop.allocator, + [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" }, + ); defer loop.allocator.free(kernel32_path); if (try fileExists(kernel32_path)) { self.kernel32_lib_dir = result_buf.toOwnedSlice(); diff --git a/std/build.zig b/std/build.zig index 1348396f59..0dbbded802 100644 --- a/std/build.zig +++ b/std/build.zig @@ -145,8 +145,8 @@ pub const Builder = struct { pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void { self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default - self.lib_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "lib"}) catch unreachable; - self.exe_dir = os.path.join(self.allocator, [][]const u8{self.prefix, "bin"}) catch unreachable; + self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable; + self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable; } pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { @@ -618,7 +618,10 @@ pub const Builder = struct { ///::dest_rel_path is relative to prefix path or it can be an absolute path pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable; + const full_dest_path = os.path.resolve( + self.allocator, + [][]const u8{ self.prefix, dest_rel_path }, + ) catch unreachable; self.pushInstalledFile(full_dest_path); const install_step = self.allocator.create(InstallFileStep) catch unreachable; @@ -653,7 +656,7 @@ pub const Builder = struct { } fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { - return os.path.resolve(self.allocator, self.build_root, rel_path) catch unreachable; + return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable; } pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 { @@ -676,7 +679,7 @@ pub const Builder = struct { if (os.path.isAbsolute(name)) { return name; } - const full_path = try os.path.join(self.allocator, [][]const u8{search_prefix, "bin", self.fmt("{}{}", name, exe_extension)}); + const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) }); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -691,7 +694,7 @@ pub const Builder = struct { } var it = mem.tokenize(PATH, []u8{os.path.delimiter}); while (it.next()) |path| { - const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)}); + const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -705,7 +708,7 @@ pub const Builder = struct { return name; } for (paths) |path| { - const full_path = try os.path.join(self.allocator, [][]const u8{path, self.fmt("{}{}", name, exe_extension)}); + const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) }); if (os.path.real(self.allocator, full_path)) |real_path| { return real_path; } else |_| { @@ -1113,7 +1116,10 @@ pub const LibExeObjStep = struct { } pub fn getOutputPath(self: *LibExeObjStep) []const u8 { - return if (self.output_path) |output_path| output_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_filename}) catch unreachable; + return if (self.output_path) |output_path| output_path else os.path.join( + self.builder.allocator, + [][]const u8{ self.builder.cache_root, self.out_filename }, + ) catch unreachable; } pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void { @@ -1126,7 +1132,10 @@ pub const LibExeObjStep = struct { } pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { - return if (self.output_h_path) |output_h_path| output_h_path else os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, self.out_h_filename}) catch unreachable; + return if (self.output_h_path) |output_h_path| output_h_path else os.path.join( + self.builder.allocator, + [][]const u8{ self.builder.cache_root, self.out_h_filename }, + ) catch unreachable; } pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { @@ -1226,7 +1235,10 @@ pub const LibExeObjStep = struct { } if (self.build_options_contents.len() > 0) { - const build_options_file = try os.path.join(builder.allocator, [][]const u8{builder.cache_root, builder.fmt("{}_build_options.zig", self.name)}); + const build_options_file = try os.path.join( + builder.allocator, + [][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) }, + ); try std.io.writeFile(build_options_file, self.build_options_contents.toSliceConst()); try zig_args.append("--pkg-begin"); try zig_args.append("build_options"); @@ -1476,7 +1488,10 @@ pub const LibExeObjStep = struct { cc_args.append("-c") catch unreachable; cc_args.append(abs_source_file) catch unreachable; - const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable; + const cache_o_src = os.path.join( + builder.allocator, + [][]const u8{ builder.cache_root, source_file }, + ) catch unreachable; if (os.path.dirname(cache_o_src)) |cache_o_dir| { try builder.makePath(cache_o_dir); } @@ -1528,7 +1543,10 @@ pub const LibExeObjStep = struct { cc_args.append("-current_version") catch unreachable; cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable; - const install_name = builder.pathFromRoot(os.path.join(builder.allocator, [][]const u8{builder.cache_root, self.major_only_filename}) catch unreachable); + const install_name = builder.pathFromRoot(os.path.join( + builder.allocator, + [][]const u8{ builder.cache_root, self.major_only_filename }, + ) catch unreachable); cc_args.append("-install_name") catch unreachable; cc_args.append(install_name) catch unreachable; } else { @@ -1594,7 +1612,10 @@ pub const LibExeObjStep = struct { cc_args.append("-c") catch unreachable; cc_args.append(abs_source_file) catch unreachable; - const cache_o_src = os.path.join(builder.allocator, [][]const u8{builder.cache_root, source_file}) catch unreachable; + const cache_o_src = os.path.join( + builder.allocator, + [][]const u8{ builder.cache_root, source_file }, + ) catch unreachable; if (os.path.dirname(cache_o_src)) |cache_o_dir| { try builder.makePath(cache_o_dir); } @@ -1757,7 +1778,10 @@ pub const TestStep = struct { return output_path; } else { const basename = self.builder.fmt("test{}", self.target.exeFileExt()); - return os.path.join(self.builder.allocator, [][]const u8{self.builder.cache_root, basename}) catch unreachable; + return os.path.join( + self.builder.allocator, + [][]const u8{ self.builder.cache_root, basename }, + ) catch unreachable; } } @@ -1979,13 +2003,22 @@ const InstallArtifactStep = struct { .builder = builder, .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make), .artifact = artifact, - .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable, - }) catch unreachable; + .dest_file = os.path.join( + builder.allocator, + [][]const u8{ dest_dir, artifact.out_filename }, + ) catch unreachable, + }; self.step.dependOn(&artifact.step); builder.pushInstalledFile(self.dest_file); if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) { - builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.major_only_filename}) catch unreachable); - builder.pushInstalledFile(os.path.join(builder.allocator, [][]const u8{builder.lib_dir, artifact.name_only_filename}) catch unreachable); + builder.pushInstalledFile(os.path.join( + builder.allocator, + [][]const u8{ builder.lib_dir, artifact.major_only_filename }, + ) catch unreachable); + builder.pushInstalledFile(os.path.join( + builder.allocator, + [][]const u8{ builder.lib_dir, artifact.name_only_filename }, + ) catch unreachable); } return self; } @@ -2141,13 +2174,19 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj const out_dir = os.path.dirname(output_path) orelse "."; const out_basename = os.path.basename(output_path); // sym link for libfoo.so.1 to libfoo.so.1.2.3 - const major_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_major_only}) catch unreachable; + const major_only_path = os.path.join( + allocator, + [][]const u8{ out_dir, filename_major_only }, + ) catch unreachable; os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| { warn("Unable to symlink {} -> {}\n", major_only_path, out_basename); return err; }; // sym link for libfoo.so to libfoo.so.1 - const name_only_path = os.path.join(allocator, [][]const u8{out_dir, filename_name_only}) catch unreachable; + const name_only_path = os.path.join( + allocator, + [][]const u8{ out_dir, filename_name_only }, + ) catch unreachable; os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| { warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only); return err; diff --git a/std/debug/index.zig b/std/debug/index.zig index 0253912d37..a1e2747df5 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -774,7 +774,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { const len = try di.coff.getPdbPath(path_buf[0..]); const raw_path = path_buf[0..len]; - const path = try os.path.resolve(allocator, raw_path); + const path = try os.path.resolve(allocator, [][]const u8{raw_path}); try di.pdb.openFile(di.coff, path); @@ -1352,7 +1352,7 @@ const LineNumberProgram = struct { 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}); + 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, diff --git a/std/event/fs.zig b/std/event/fs.zig index 97a79bed39..fd0fe434cb 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -871,7 +871,7 @@ pub fn Watch(comptime V: type) type { } async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V { - const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path); + const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path}); var resolved_path_consumed = false; defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path); @@ -1336,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { } async fn testFsWatch(loop: *Loop) !void { - const file_path = try os.path.join(loop.allocator, [][]const u8{test_tmp_dir, "file.txt"}); + const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" }); defer loop.allocator.free(file_path); const contents = diff --git a/std/mem.zig b/std/mem.zig index 178a5f6c6f..48d1cb930c 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -882,42 +882,37 @@ pub const SplitIterator = struct { } }; -/// Naively combines a series of strings with a separator. +/// Naively combines a series of slices with a separator. /// Allocates memory for the result, which must be freed by the caller. -pub fn join(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { - comptime assert(strings.len >= 1); - var total_strings_len: usize = strings.len; // 1 sep per string - { - comptime var string_i = 0; - inline while (string_i < strings.len) : (string_i += 1) { - const arg = ([]const u8)(strings[string_i]); - total_strings_len += arg.len; - } - } +pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []const u8) ![]u8 { + if (slices.len == 0) return (([*]u8)(undefined))[0..0]; - const buf = try allocator.alloc(u8, total_strings_len); + const total_len = blk: { + var sum: usize = separator.len * (slices.len - 1); + for (slices) |slice| + sum += slice.len; + break :blk sum; + }; + + const buf = try allocator.alloc(u8, total_len); errdefer allocator.free(buf); - var buf_index: usize = 0; - comptime var string_i = 0; - inline while (true) { - const arg = ([]const u8)(strings[string_i]); - string_i += 1; - copy(u8, buf[buf_index..], arg); - buf_index += arg.len; - if (string_i >= strings.len) break; - if (buf[buf_index - 1] != sep) { - buf[buf_index] = sep; - buf_index += 1; - } + copy(u8, buf, slices[0]); + var buf_index: usize = slices[0].len; + for (slices[1..]) |slice| { + copy(u8, buf[buf_index..], separator); + buf_index += separator.len; + copy(u8, buf[buf_index..], slice); + buf_index += slice.len; } - return allocator.shrink(u8, buf, buf_index); + // No need for shrink since buf is exactly the correct size. + return buf; } test "mem.join" { - assert(eql(u8, try join(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); - assert(eql(u8, try join(debug.global_allocator, ',', "a"), "a")); + assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); + assert(eql(u8, try join(debug.global_allocator, ",", [][]const u8{"a"}), "a")); } test "testStringEquality" { diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 2651310c98..6635b76976 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -574,7 +574,7 @@ pub const ChildProcess = struct { // to match posix semantics const app_name = x: { if (self.cwd) |cwd| { - const resolved = try os.path.resolve(self.allocator, cwd, self.argv[0]); + const resolved = try os.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] }); defer self.allocator.free(resolved); break :x try cstr.addNullByte(self.allocator, resolved); } else { diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig index a0315b4511..f5e0b78eec 100644 --- a/std/os/get_app_data_dir.zig +++ b/std/os/get_app_data_dir.zig @@ -30,7 +30,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD error.OutOfMemory => return error.OutOfMemory, }; defer allocator.free(global_dir); - return os.path.join(allocator, [][]const u8{global_dir, appname}); + return os.path.join(allocator, [][]const u8{ global_dir, appname }); }, os.windows.E_OUTOFMEMORY => return error.OutOfMemory, else => return error.AppDataDirUnavailable, @@ -41,14 +41,14 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD // TODO look in /etc/passwd return error.AppDataDirUnavailable; }; - return os.path.join(allocator, [][]const u8{home_dir, "Library", "Application Support", appname}); + return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname }); }, builtin.Os.linux, builtin.Os.freebsd => { const home_dir = os.getEnvPosix("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; }; - return os.path.join(allocator, [][]const u8{home_dir, ".local", "share", appname}); + return os.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname }); }, else => @compileError("Unsupported OS"), } @@ -67,4 +67,3 @@ test "std.os.getAppDataDir" { // We can't actually validate the result _ = getAppDataDir(allocator, "zig") catch return; } - diff --git a/std/os/index.zig b/std/os/index.zig index d17b6f4f40..8e9876c36b 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -1284,7 +1284,7 @@ pub fn makeDirPosix(dir_path: []const u8) !void { /// 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, full_path); + const resolved_path = try path.resolve(allocator, [][]const u8{full_path}); defer allocator.free(resolved_path); var end_index: usize = resolved_path.len; @@ -2304,18 +2304,17 @@ 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 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); + 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; diff --git a/std/os/path.zig b/std/os/path.zig index 5a5b1b7772..266a77b97c 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -33,63 +33,103 @@ pub fn isSep(byte: u8) bool { } } -/// Naively combines a series of paths with the native path seperator. -/// Allocates memory for the result, which must be freed by the caller. +/// This is different from mem.join in that the separator will not be repeated if +/// it is found at the end or beginning of a pair of consecutive paths. +fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 { + if (paths.len == 0) return (([*]u8)(undefined))[0..0]; -pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 { - assert(paths.len >= 1); - var total_paths_len: usize = paths.len; // 1 sep per path - { - var path_i: usize = 0; - while (path_i < paths.len) : (path_i += 1) { - const arg = ([]const u8)(paths[path_i]); - total_paths_len += arg.len; + const total_len = blk: { + var sum: usize = paths[0].len; + var i: usize = 1; + while (i < paths.len) : (i += 1) { + const prev_path = paths[i - 1]; + const this_path = paths[i]; + const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator); + const this_sep = (this_path.len != 0 and this_path[0] == separator); + sum += @boolToInt(!prev_sep and !this_sep); + sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; } - } + break :blk sum; + }; - const buf = try allocator.alloc(u8, total_paths_len); + const buf = try allocator.alloc(u8, total_len); errdefer allocator.free(buf); - var buf_index: usize = 0; - var path_i: usize = 0; - while (true) { - const arg = ([]const u8)(paths[path_i]); - path_i += 1; - mem.copy(u8, buf[buf_index..], arg); - buf_index += arg.len; - if (path_i >= paths.len) break; - if (buf_index > 0 and buf[buf_index - 1] != sep) { - buf[buf_index] = sep; + mem.copy(u8, buf, paths[0]); + var buf_index: usize = paths[0].len; + var i: usize = 1; + while (i < paths.len) : (i += 1) { + const prev_path = paths[i - 1]; + const this_path = paths[i]; + const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator); + const this_sep = (this_path.len != 0 and this_path[0] == separator); + if (!prev_sep and !this_sep) { + buf[buf_index] = separator; buf_index += 1; } + const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path; + mem.copy(u8, buf[buf_index..], adjusted_path); + buf_index += adjusted_path.len; } - return allocator.shrink(u8, buf, buf_index); + // No need for shrink since buf is exactly the correct size. + return buf; +} + +pub const join = if (is_windows) joinWindows else joinPosix; + +/// Naively combines a series of paths with the native path seperator. +/// Allocates memory for the result, which must be freed by the caller. +pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { + return joinSep(allocator, sep_windows, paths); +} + +/// Naively combines a series of paths with the native path seperator. +/// Allocates memory for the result, which must be freed by the caller. +pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { + return joinSep(allocator, sep_posix, paths); +} + +fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { + var buf: [1024]u8 = undefined; + const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; + const actual = joinWindows(a, paths) catch @panic("fail"); + debug.assertOrPanic(mem.eql(u8, actual, expected)); +} + +fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { + var buf: [1024]u8 = undefined; + const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; + const actual = joinPosix(a, paths) catch @panic("fail"); + debug.assertOrPanic(mem.eql(u8, actual, expected)); } test "os.path.join" { - switch (builtin.os) { - Os.windows => { - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b", "c"}), "c:\\a\\b\\c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\b\\", "c"}), "c:\\a\\b\\c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\", "a", "b\\", "c"}), "c:\\a\\b\\c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"c:\\a\\", "b\\", "c"}), "c:\\a\\b\\c")); - assert(mem.eql(u8, try join( debug.global_allocator - , [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std" - , "io.zig"}) - , "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig")); - }, - else => { - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b", "c"}), "/a/b/c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/b/", "c"}), "/a/b/c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/", "a", "b/", "c"}), "/a/b/c")); - assert(mem.eql(u8, try join(debug.global_allocator, [][]const u8{"/a/", "b/", "c"}), "/a/b/c")); - assert(mem.eql(u8, try join( debug.global_allocator - , [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std" - , "io.zig"}) - , "/home/andy/dev/zig/build/lib/zig/std/io.zig")); - } - } + testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); + testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); + testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c"); + + testJoinWindows([][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c"); + testJoinWindows([][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c"); + + testJoinWindows( + [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" }, + "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", + ); + + testJoinPosix([][]const u8{ "/a/b", "c" }, "/a/b/c"); + testJoinPosix([][]const u8{ "/a/b/", "c" }, "/a/b/c"); + + testJoinPosix([][]const u8{ "/", "a", "b/", "c" }, "/a/b/c"); + testJoinPosix([][]const u8{ "/a/", "b/", "c" }, "/a/b/c"); + + testJoinPosix( + [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" }, + "/home/andy/dev/zig/build/lib/zig/std/io.zig", + ); + + testJoinPosix([][]const u8{ "a", "/c" }, "a/c"); + testJoinPosix([][]const u8{ "a/", "/c" }, "a/c"); } pub fn isAbsolute(path: []const u8) bool { @@ -335,18 +375,8 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { return true; } -/// Converts the command line arguments into a slice and calls `resolveSlice`. -pub fn resolve(allocator: *Allocator, args: ...) ![]u8 { - var paths: [args.len][]const u8 = undefined; - comptime var arg_i = 0; - inline while (arg_i < args.len) : (arg_i += 1) { - paths[arg_i] = args[arg_i]; - } - return resolveSlice(allocator, paths); -} - /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. -pub fn resolveSlice(allocator: *Allocator, paths: []const []const u8) ![]u8 { +pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (is_windows) { return resolveWindows(allocator, paths); } else { @@ -625,7 +655,10 @@ test "os.path.resolveWindows" { const parsed_cwd = windowsParsePath(cwd); { const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }); - const expected = try join(debug.global_allocator, [][]const u8{ parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"}); + const expected = try join(debug.global_allocator, [][]const u8{ + parsed_cwd.disk_designator, + "usr\\local\\lib\\zig\\std\\array_list.zig", + }); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } @@ -633,7 +666,10 @@ test "os.path.resolveWindows" { } { const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" }); - const expected = try join(debug.global_allocator, [][]const u8{ cwd, "usr\\local\\lib\\zig" }); + const expected = try join(debug.global_allocator, [][]const u8{ + cwd, + "usr\\local\\lib\\zig", + }); if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } diff --git a/test/cli.zig b/test/cli.zig index 0980e8c2d8..745da4dd80 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -27,7 +27,7 @@ pub fn main() !void { std.debug.warn("Expected second argument to be cache root directory path\n"); return error.InvalidArgs; }); - const zig_exe = try os.path.resolve(a, zig_exe_rel); + const zig_exe = try os.path.resolve(a, [][]const u8{zig_exe_rel}); const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" }); const TestFn = fn ([]const u8, []const u8) anyerror!void; diff --git a/test/tests.zig b/test/tests.zig index fac941cbde..670c410509 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -439,7 +439,10 @@ pub const CompareOutputContext = struct { pub fn addCase(self: *CompareOutputContext, case: TestCase) void { const b = self.b; - const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable; + const root_src = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, case.sources.items[0].filename }, + ) catch unreachable; switch (case.special) { Special.Asm => { @@ -452,7 +455,10 @@ pub const CompareOutputContext = struct { exe.addAssemblyFile(root_src); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -476,7 +482,10 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -499,7 +508,10 @@ pub const CompareOutputContext = struct { } for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); exe.step.dependOn(&write_src.step); } @@ -572,8 +584,14 @@ pub const CompileErrorContext = struct { const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); const b = self.context.b; - const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable; - const obj_path = os.path.join(b.allocator, [][]const u8{b.cache_root, "test.o"}) catch unreachable; + const root_src = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, self.case.sources.items[0].filename }, + ) catch unreachable; + const obj_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, "test.o" }, + ) catch unreachable; var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; @@ -721,7 +739,10 @@ pub const CompileErrorContext = struct { self.step.dependOn(&compile_and_cmp_errors.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); compile_and_cmp_errors.step.dependOn(&write_src.step); } @@ -852,7 +873,10 @@ pub const TranslateCContext = struct { const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); const b = self.context.b; - const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, self.case.sources.items[0].filename}) catch unreachable; + const root_src = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, self.case.sources.items[0].filename }, + ) catch unreachable; var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; @@ -986,7 +1010,10 @@ pub const TranslateCContext = struct { self.step.dependOn(&translate_c_and_cmp.step); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); translate_c_and_cmp.step.dependOn(&write_src.step); } @@ -1101,7 +1128,10 @@ pub const GenHContext = struct { pub fn addCase(self: *GenHContext, case: *const TestCase) void { const b = self.b; - const root_src = os.path.join(b.allocator, [][]const u8{b.cache_root, case.sources.items[0].filename}) catch unreachable; + const root_src = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, case.sources.items[0].filename }, + ) catch unreachable; const mode = builtin.Mode.Debug; const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", case.name, @tagName(mode)) catch unreachable; @@ -1113,7 +1143,10 @@ pub const GenHContext = struct { obj.setBuildMode(mode); for (case.sources.toSliceConst()) |src_file| { - const expanded_src_path = os.path.join(b.allocator, [][]const u8{b.cache_root, src_file.filename}) catch unreachable; + const expanded_src_path = os.path.join( + b.allocator, + [][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; const write_src = b.addWriteFile(expanded_src_path, src_file.source); obj.step.dependOn(&write_src.step); } From 38a77161949dbae036d4172ceba2f698de9f18a1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 10:55:23 -0500 Subject: [PATCH 148/218] fixups --- std/mem.zig | 105 ++++++++++++++++++---------------------------------- 1 file changed, 35 insertions(+), 70 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index aac07ece7d..a6cbae744f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -856,65 +856,31 @@ pub const TokenIterator = struct { } }; -/// Naively combines a series of strings with a separator. -/// Allocates memory for the result, which must be freed by the caller. -pub fn join(allocator: *Allocator, sep: u8, strings: []const []const u8) ![]u8 { - assert(strings.len >= 1); - var total_strings_len: usize = strings.len; // 1 sep per string - { - var string_i: usize = 0; - while (string_i < strings.len) : (string_i += 1) { - const arg = ([]const u8)(strings[string_i]); - total_strings_len += arg.len; - } +pub const SplitIterator = struct { + buffer: []const u8, + index: ?usize, + delimiter: []const u8, + + /// Returns a slice of the next field, or null if splitting is complete. + pub fn next(self: *SplitIterator) ?[]const u8 { + const start = self.index orelse return null; + const end = if (indexOfPos(u8, self.buffer, start, self.delimiter)) |delim_start| blk: { + self.index = delim_start + self.delimiter.len; + break :blk delim_start; + } else blk: { + self.index = null; + break :blk self.buffer.len; + }; + return self.buffer[start..end]; } - const buf = try allocator.alloc(u8, total_strings_len); - errdefer allocator.free(buf); - - var buf_index: usize = 0; - var string_i: usize = 0; - while (true) { - const arg = ([]const u8)(strings[string_i]); - string_i += 1; - copy(u8, buf[buf_index..], arg); - buf_index += arg.len; - if (string_i >= strings.len) break; - buf[buf_index] = sep; - buf_index += 1; + /// Returns a slice of the remaining bytes. Does not affect iterator state. + pub fn rest(self: SplitIterator) []const u8 { + const end = self.buffer.len; + const start = self.index orelse end; + return self.buffer[start..end]; } - - return allocator.shrink(u8, buf, buf_index); -} - -test "mem.join" { - var str: []u8 = try join(debug.global_allocator, ',', [][]const u8{ "a", "b", "c" }); - errdefer debug.global_allocator.free(str); - assert(eql(u8, str, "a,b,c")); - debug.global_allocator.free(str); - - str = try join(debug.global_allocator, ',', [][]const u8{"a"}); - assert(eql(u8, str, "a")); - debug.global_allocator.free(str); - - str = try join(debug.global_allocator, ',', [][]const u8{ "a", ([]const u8)(""), "b", ([]const u8)(""), "c" }); - assert(eql(u8, str, "a,,b,,c")); - debug.global_allocator.free(str); -} - -/// Naively combines a series of strings with a separator inline. -/// Allocates memory for the result, which must be freed by the caller. -pub fn joinInline(allocator: *Allocator, sep: u8, strings: ...) ![]u8 { - comptime assert(strings.len >= 1); - var total_strings_len: usize = strings.len; // 1 sep per string - { - comptime var string_i = 0; - inline while (string_i < strings.len) : (string_i += 1) { - const arg = ([]const u8)(strings[string_i]); - total_strings_len += arg.len; - } - } -} +}; /// Naively combines a series of slices with a separator. /// Allocates memory for the result, which must be freed by the caller. @@ -931,26 +897,25 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons const buf = try allocator.alloc(u8, total_len); errdefer allocator.free(buf); - var buf_index: usize = 0; - comptime var string_i = 0; - inline while (true) { - const arg = ([]const u8)(strings[string_i]); - string_i += 1; - copy(u8, buf[buf_index..], arg); - buf_index += arg.len; - if (string_i >= strings.len) break; - buf[buf_index] = sep; - buf_index += 1; + copy(u8, buf, slices[0]); + var buf_index: usize = slices[0].len; + for (slices[1..]) |slice| { + copy(u8, buf[buf_index..], separator); + buf_index += separator.len; + copy(u8, buf[buf_index..], slice); + buf_index += slice.len; } // No need for shrink since buf is exactly the correct size. return buf; } -test "mem.joinInline" { - assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", "c"), "a,b,c")); - assert(eql(u8, try joinInline(debug.global_allocator, ',', "a", "b", ([]const u8)(""), "c"), "a,b,,c")); - assert(eql(u8, try joinInline(debug.global_allocator, ',', "a"), "a")); +test "mem.join" { + var buf: [1024]u8 = undefined; + const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; + assert(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); + assert(eql(u8, try join(a, ",", [][]const u8{"a"}), "a")); + assert(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); } test "testStringEquality" { From 2b2bf53a49616192e2b2bdf40b88400964ff1500 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 11:40:56 -0500 Subject: [PATCH 149/218] better error message when LLVM does not understand a triple --- src/codegen.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index c5de05e372..f010430e14 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7553,7 +7553,13 @@ static void init(CodeGen *g) { LLVMTargetRef target_ref; char *err_msg = nullptr; if (LLVMGetTargetFromTriple(buf_ptr(&g->triple_str), &target_ref, &err_msg)) { - zig_panic("unable to create target based on: %s", buf_ptr(&g->triple_str)); + fprintf(stderr, + "Zig is expecting LLVM to understand this target: '%s'\n" + "However LLVM responded with: \"%s\"\n" + "Zig is unable to continue. This is a bug in Zig:\n" + "https://github.com/ziglang/zig/issues/438\n" + , buf_ptr(&g->triple_str), err_msg); + exit(1); } bool is_optimized = g->build_mode != BuildModeDebug; From 7843c96df87007561c107d11afa2fa74b46667fd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 12:18:01 -0500 Subject: [PATCH 150/218] build: make sure LLVM is exactly correct * check the version to be the correct major version * ensure that it has all the default targets enabled --- cmake/Findllvm.cmake | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/cmake/Findllvm.cmake b/cmake/Findllvm.cmake index 70d50f9843..2f0afa09b7 100644 --- a/cmake/Findllvm.cmake +++ b/cmake/Findllvm.cmake @@ -15,14 +15,50 @@ find_program(LLVM_CONFIG_EXE "c:/msys64/mingw64/bin" "C:/Libraries/llvm-7.0.0/bin") +if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND") + message(FATAL_ERROR "unable to find llvm-config") +endif() + execute_process( COMMAND ${LLVM_CONFIG_EXE} --version OUTPUT_VARIABLE LLVM_CONFIG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) -if(LLVM_CONFIG_VERSION VERSION_LESS 7) - message(FATAL_ERROR "expected LLVM version >=7 but found ${LLVM_CONFIG_VERSION}") +if("${LLVM_CONFIG_VERSION}" VERSION_LESS 7) + message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}") endif() +if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 8) + message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}") +endif() +if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 8) + message(FATAL_ERROR "expected LLVM 7.x but found ${LLVM_CONFIG_VERSION}") +endif() + +execute_process( + COMMAND ${LLVM_CONFIG_EXE} --targets-built + OUTPUT_VARIABLE LLVM_TARGETS_BUILT_SPACES + OUTPUT_STRIP_TRAILING_WHITESPACE) +string(REPLACE " " ";" LLVM_TARGETS_BUILT "${LLVM_TARGETS_BUILT_SPACES}") +function(NEED_TARGET TARGET_NAME) + list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index) + if (${_index} EQUAL -1) + message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.") + endif() +endfunction(NEED_TARGET) +NEED_TARGET("AArch64") +NEED_TARGET("AMDGPU") +NEED_TARGET("ARM") +NEED_TARGET("BPF") +NEED_TARGET("Hexagon") +NEED_TARGET("Lanai") +NEED_TARGET("Mips") +NEED_TARGET("MSP430") +NEED_TARGET("NVPTX") +NEED_TARGET("PowerPC") +NEED_TARGET("Sparc") +NEED_TARGET("SystemZ") +NEED_TARGET("X86") +NEED_TARGET("XCore") if(NOT(CMAKE_BUILD_TYPE STREQUAL "Debug") OR ZIG_STATIC) execute_process( From f330eebe4bc6a036846cf05706f72855627c705a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 16:02:45 -0500 Subject: [PATCH 151/218] fix using the result of @intCast to u0 closes #1817 --- src/all_types.hpp | 7 ++++++ src/codegen.cpp | 40 +++++++++++++++++++++++++---------- src/ir.cpp | 31 +++++++++++++++++++++++++++ src/ir_print.cpp | 9 ++++++++ test/runtime_safety.zig | 17 +++++++++++++++ test/stage1/behavior/cast.zig | 11 ++++++++++ test/stage1/behavior/eval.zig | 6 ------ 7 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 5af4e71157..842c9ae904 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2239,6 +2239,7 @@ enum IrInstructionId { IrInstructionIdCheckRuntimeScope, IrInstructionIdVectorToArray, IrInstructionIdArrayToVector, + IrInstructionIdAssertZero, }; struct IrInstruction { @@ -3381,6 +3382,12 @@ struct IrInstructionVectorToArray { LLVMValueRef tmp_ptr; }; +struct IrInstructionAssertZero { + IrInstruction base; + + IrInstruction *target; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index f010430e14..3bfd7cdfc5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1651,10 +1651,25 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } +static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) { + LLVMValueRef zero = LLVMConstNull(int_type->type_ref); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdCastTruncatedData); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return nullptr; +} + static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, ZigType *wanted_type, LLVMValueRef expr_val) { assert(actual_type->id == wanted_type->id); + assert(expr_val != nullptr); uint64_t actual_bits; uint64_t wanted_bits; @@ -1707,17 +1722,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z if (!want_runtime_safety) return nullptr; - LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return nullptr; + return gen_assert_zero(g, expr_val, actual_type); } LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); if (!want_runtime_safety) { @@ -5209,6 +5214,17 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab return gen_load_untyped(g, casted_ptr, 0, false, ""); } +static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable, + IrInstructionAssertZero *instruction) +{ + LLVMValueRef target = ir_llvm_value(g, instruction->target); + ZigType *int_type = instruction->target->value.type; + if (ir_want_runtime_safety(g, &instruction->base)) { + return gen_assert_zero(g, target, int_type); + } + return nullptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5458,6 +5474,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); case IrInstructionIdVectorToArray: return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); + case IrInstructionIdAssertZero: + return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 02b2b12230..00d358552a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) return IrInstructionIdArrayToVector; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertZero *) { + return IrInstructionIdAssertZero; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2858,6 +2862,19 @@ static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *so return &instruction->base; } +static IrInstruction *ir_build_assert_zero(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *target) +{ + IrInstructionAssertZero *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ira->codegen->builtin_types.entry_void; + instruction->target = target; + + ir_ref_instruction(target, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -10395,6 +10412,18 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction return result; } + // If the destination integer type has no bits, then we can emit a comptime + // zero. However, we still want to emit a runtime safety check to make sure + // the target is zero. + if (!type_has_bits(wanted_type)) { + assert(wanted_type->id == ZigTypeIdInt); + assert(type_has_bits(target->value.type)); + ir_build_assert_zero(ira, source_instr, target); + IrInstruction *result = ir_const_unsigned(ira, source_instr, 0); + result->value.type = wanted_type; + return result; + } + IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope, source_instr->source_node, target); result->value.type = wanted_type; @@ -21705,6 +21734,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdCmpxchgGen: case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: + case IrInstructionIdAssertZero: zig_unreachable(); case IrInstructionIdReturn: @@ -22103,6 +22133,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAtomicRmw: case IrInstructionIdCmpxchgGen: case IrInstructionIdCmpxchgSrc: + case IrInstructionIdAssertZero: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e19aa6dda8..75da24d1a9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -984,6 +984,12 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i fprintf(irp->f, ")"); } +static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) { + fprintf(irp->f, "AssertZero("); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1843,6 +1849,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdVectorToArray: ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); break; + case IrInstructionIdAssertZero: + ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 7c13f5b6fa..7de43b45f4 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -362,6 +362,23 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + // @intCast a runtime integer to u0 actually results in a comptime-known value, + // but we still emit a safety check to ensure the integer was 0 and thus + // did not truncate information. + cases.addRuntimeSafety("@intCast to u0", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\ + \\pub fn main() void { + \\ bar(1, 1); + \\} + \\ + \\fn bar(one: u1, not_zero: i32) void { + \\ var x = one << @intCast(u0, not_zero); + \\} + ); + // This case makes sure that the code compiles and runs. There is not actually a special // runtime safety check having to do specifically with error return traces across suspend points. cases.addRuntimeSafety("error return trace across suspend points", diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 61ddcd8135..27f685a96e 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -471,3 +471,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" { const x = @intToEnum(E, 0); assertOrPanic(x == E.A); } + +test "@intCast to u0 and use the result" { + const S = struct { + fn doTheTest(zero: u1, one: u1, bigzero: i32) void { + assertOrPanic((one << @intCast(u0, bigzero)) == 1); + assertOrPanic((zero << @intCast(u0, bigzero)) == 0); + } + }; + S.doTheTest(0, 1, 0); + comptime S.doTheTest(0, 1, 0); +} diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 3e8af0524f..0d1ecfab5b 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -697,12 +697,6 @@ test "bit shift a u1" { assertOrPanic(y == 1); } -test "@intCast to a u0" { - var x: u8 = 0; - var y: u0 = @intCast(u0, x); - assertOrPanic(y == 0); -} - test "@bytesToslice on a packed struct" { const F = packed struct { a: u8, From be6d022257d8d7e99bd080823d4d8f0175f320c5 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Thu, 7 Feb 2019 21:28:37 +0100 Subject: [PATCH 152/218] Make ThreadSafeFixedBufferAllocator alias FixedBufferAllocator when --single-threaded Fixes #1910 --- std/heap.zig | 90 ++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/std/heap.zig b/std/heap.zig index 1403f8e831..8a5ebf134c 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -321,51 +321,57 @@ pub const FixedBufferAllocator = struct { fn free(allocator: *Allocator, bytes: []u8) void {} }; -/// lock free -pub const ThreadSafeFixedBufferAllocator = struct { - allocator: Allocator, - end_index: usize, - buffer: []u8, +pub const ThreadSafeFixedBufferAllocator = blk: { + if (builtin.single_threaded) { + break :blk FixedBufferAllocator; + } else { + /// lock free + break :blk struct { + allocator: Allocator, + end_index: usize, + buffer: []u8, - pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator { - return ThreadSafeFixedBufferAllocator{ - .allocator = Allocator{ - .allocFn = alloc, - .reallocFn = realloc, - .freeFn = free, - }, - .buffer = buffer, - .end_index = 0, + pub fn init(buffer: []u8) ThreadSafeFixedBufferAllocator { + return ThreadSafeFixedBufferAllocator{ + .allocator = Allocator{ + .allocFn = alloc, + .reallocFn = realloc, + .freeFn = free, + }, + .buffer = buffer, + .end_index = 0, + }; + } + + fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { + const self = @fieldParentPtr(ThreadSafeFixedBufferAllocator, "allocator", allocator); + var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst); + while (true) { + const addr = @ptrToInt(self.buffer.ptr) + end_index; + const rem = @rem(addr, alignment); + const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); + const adjusted_index = end_index + march_forward_bytes; + const new_end_index = adjusted_index + n; + if (new_end_index > self.buffer.len) { + return error.OutOfMemory; + } + end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse return self.buffer[adjusted_index..new_end_index]; + } + } + + fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { + if (new_size <= old_mem.len) { + return old_mem[0..new_size]; + } else { + const result = try alloc(allocator, new_size, alignment); + mem.copy(u8, result, old_mem); + return result; + } + } + + fn free(allocator: *Allocator, bytes: []u8) void {} }; } - - fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { - const self = @fieldParentPtr(ThreadSafeFixedBufferAllocator, "allocator", allocator); - var end_index = @atomicLoad(usize, &self.end_index, builtin.AtomicOrder.SeqCst); - while (true) { - const addr = @ptrToInt(self.buffer.ptr) + end_index; - const rem = @rem(addr, alignment); - const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); - const adjusted_index = end_index + march_forward_bytes; - const new_end_index = adjusted_index + n; - if (new_end_index > self.buffer.len) { - return error.OutOfMemory; - } - end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse return self.buffer[adjusted_index..new_end_index]; - } - } - - fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { - if (new_size <= old_mem.len) { - return old_mem[0..new_size]; - } else { - const result = try alloc(allocator, new_size, alignment); - mem.copy(u8, result, old_mem); - return result; - } - } - - fn free(allocator: *Allocator, bytes: []u8) void {} }; pub fn stackFallback(comptime size: usize, fallback_allocator: *Allocator) StackFallbackAllocator(size) { From c2db077574be841da586fa62d67619c901dd535d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Feb 2019 18:18:47 -0500 Subject: [PATCH 153/218] std.debug.assert: remove special case for test builds Previously, std.debug.assert would `@panic` in test builds, if the assertion failed. Now, it's always `unreachable`. This makes release mode test builds more accurately test the actual code that will be run. However this requires tests to call `std.testing.expect` rather than `std.debug.assert` to make sure output is correct. Here is the explanation of when to use either one, copied from the assert doc comments: Inside a test block, it is best to use the `std.testing` module rather than assert, because assert may not detect a test failure in ReleaseFast and ReleaseSafe mode. Outside of a test block, assert is the correct function to use. closes #1304 --- CMakeLists.txt | 1 + doc/docgen.zig | 4 +- src-self-hosted/arg.zig | 23 +- src-self-hosted/test.zig | 4 +- src/ir.cpp | 24 +- std/array_list.zig | 106 ++--- std/atomic/queue.zig | 23 +- std/atomic/stack.zig | 5 +- std/base64.zig | 13 +- std/buf_map.zig | 16 +- std/buf_set.zig | 6 +- std/buffer.zig | 15 +- std/crypto/chacha20.zig | 15 +- std/crypto/poly1305.zig | 2 +- std/crypto/test.zig | 9 +- std/crypto/x25519.zig | 24 +- std/cstr.zig | 6 +- std/debug/index.zig | 38 +- std/dynamic_library.zig | 3 +- std/event/channel.zig | 9 +- std/event/fs.zig | 9 +- std/event/future.zig | 3 +- std/event/group.zig | 6 +- std/event/lock.zig | 3 +- std/event/loop.zig | 5 +- std/event/net.zig | 4 +- std/event/rwlock.zig | 7 +- std/fmt/index.zig | 158 ++++---- std/hash/adler.zig | 12 +- std/hash/crc.zig | 25 +- std/hash/fnv.zig | 18 +- std/hash/siphash.zig | 15 +- std/hash_map.zig | 59 +-- std/heap.zig | 55 +-- std/index.zig | 15 +- std/io.zig | 17 +- std/io_test.zig | 202 +++++----- std/json.zig | 17 +- std/json_test.zig | 6 +- std/lazy_init.zig | 9 +- std/linked_list.zig | 29 +- std/math/acos.zig | 38 +- std/math/acosh.zig | 30 +- std/math/asin.zig | 46 +-- std/math/asinh.zig | 54 +-- std/math/atan.zig | 42 +- std/math/atan2.zig | 110 +++--- std/math/atanh.zig | 38 +- std/math/big/int.zig | 367 +++++++++--------- std/math/cbrt.zig | 50 +-- std/math/ceil.zig | 38 +- std/math/complex/abs.zig | 4 +- std/math/complex/acos.zig | 6 +- std/math/complex/acosh.zig | 6 +- std/math/complex/arg.zig | 4 +- std/math/complex/asin.zig | 6 +- std/math/complex/asinh.zig | 6 +- std/math/complex/atan.zig | 10 +- std/math/complex/atanh.zig | 6 +- std/math/complex/conj.zig | 4 +- std/math/complex/cos.zig | 6 +- std/math/complex/cosh.zig | 10 +- std/math/complex/exp.zig | 10 +- std/math/complex/index.zig | 16 +- std/math/complex/log.zig | 6 +- std/math/complex/pow.zig | 6 +- std/math/complex/proj.zig | 4 +- std/math/complex/sin.zig | 6 +- std/math/complex/sinh.zig | 10 +- std/math/complex/sqrt.zig | 10 +- std/math/complex/tan.zig | 6 +- std/math/complex/tanh.zig | 10 +- std/math/copysign.zig | 32 +- std/math/cos.zig | 42 +- std/math/cosh.zig | 42 +- std/math/exp2.zig | 32 +- std/math/expm1.zig | 38 +- std/math/fabs.zig | 38 +- std/math/floor.zig | 56 +-- std/math/fma.zig | 34 +- std/math/frexp.zig | 34 +- std/math/hypot.zig | 58 +-- std/math/ilogb.zig | 46 +-- std/math/index.zig | 335 ++++++++-------- std/math/isfinite.zig | 26 +- std/math/isinf.zig | 74 ++-- std/math/isnan.zig | 14 +- std/math/isnormal.zig | 20 +- std/math/ln.zig | 46 +-- std/math/log.zig | 26 +- std/math/log10.zig | 46 +-- std/math/log1p.zig | 58 +-- std/math/log2.zig | 42 +- std/math/modf.zig | 58 +-- std/math/pow.zig | 94 ++--- std/math/powi.zig | 122 +++--- std/math/round.zig | 42 +- std/math/scalbn.zig | 10 +- std/math/signbit.zig | 20 +- std/math/sin.zig | 52 +-- std/math/sinh.zig | 42 +- std/math/sqrt.zig | 104 ++--- std/math/tan.zig | 50 +-- std/math/tanh.zig | 46 +-- std/math/trunc.zig | 38 +- std/mem.zig | 317 +++++++-------- std/meta/index.zig | 151 +++---- std/meta/trait.zig | 133 +++---- std/mutex.zig | 6 +- std/os/child_process.zig | 1 - std/os/index.zig | 9 +- std/os/linux/test.zig | 12 +- std/os/path.zig | 113 +++--- std/os/test.zig | 16 +- std/os/time.zig | 9 +- std/rand/index.zig | 161 ++++---- std/rb.zig | 5 +- std/segmented_list.zig | 31 +- std/sort.zig | 17 +- std/special/compiler_rt/divti3_test.zig | 4 +- std/special/compiler_rt/extendXfYf2_test.zig | 1 - std/special/compiler_rt/fixdfdi_test.zig | 4 +- std/special/compiler_rt/fixdfsi_test.zig | 4 +- std/special/compiler_rt/fixdfti_test.zig | 4 +- std/special/compiler_rt/fixint_test.zig | 4 +- std/special/compiler_rt/fixsfdi_test.zig | 4 +- std/special/compiler_rt/fixsfsi_test.zig | 4 +- std/special/compiler_rt/fixsfti_test.zig | 4 +- std/special/compiler_rt/fixtfdi_test.zig | 4 +- std/special/compiler_rt/fixtfsi_test.zig | 4 +- std/special/compiler_rt/fixtfti_test.zig | 4 +- std/special/compiler_rt/fixunsdfdi_test.zig | 4 +- std/special/compiler_rt/fixunsdfsi_test.zig | 4 +- std/special/compiler_rt/fixunsdfti_test.zig | 4 +- std/special/compiler_rt/fixunssfdi_test.zig | 4 +- std/special/compiler_rt/fixunssfsi_test.zig | 4 +- std/special/compiler_rt/fixunssfti_test.zig | 4 +- std/special/compiler_rt/fixunstfdi_test.zig | 4 +- std/special/compiler_rt/fixunstfsi_test.zig | 4 +- std/special/compiler_rt/fixunstfti_test.zig | 4 +- std/special/compiler_rt/floattidf_test.zig | 4 +- std/special/compiler_rt/floattisf_test.zig | 4 +- std/special/compiler_rt/floattitf_test.zig | 4 +- std/special/compiler_rt/floatunditf_test.zig | 1 - std/special/compiler_rt/floatunsitf_test.zig | 1 - std/special/compiler_rt/floatuntidf_test.zig | 4 +- std/special/compiler_rt/floatuntisf_test.zig | 4 +- std/special/compiler_rt/floatuntitf_test.zig | 4 +- std/special/compiler_rt/index.zig | 5 +- std/special/compiler_rt/muloti4_test.zig | 4 +- std/special/compiler_rt/multi3_test.zig | 4 +- std/special/compiler_rt/udivmoddi4_test.zig | 6 +- std/special/compiler_rt/udivmodti4_test.zig | 6 +- std/special/init-lib/src/main.zig | 4 +- std/statically_initialized_mutex.zig | 5 +- std/testing.zig | 152 ++++++++ std/unicode.zig | 119 +++--- std/zig/ast.zig | 3 +- std/zig/parser_test.zig | 2 +- std/zig/tokenizer.zig | 2 +- test/cli.zig | 10 +- test/stage1/behavior/align.zig | 72 ++-- test/stage1/behavior/alignof.zig | 6 +- test/stage1/behavior/array.zig | 110 +++--- test/stage1/behavior/asm.zig | 4 +- test/stage1/behavior/atomics.zig | 32 +- test/stage1/behavior/bit_shifting.zig | 10 +- test/stage1/behavior/bitcast.zig | 8 +- test/stage1/behavior/bitreverse.zig | 86 ++-- test/stage1/behavior/bool.zig | 20 +- test/stage1/behavior/bswap.zig | 42 +- test/stage1/behavior/bugs/1076.zig | 4 +- test/stage1/behavior/bugs/1277.zig | 2 +- test/stage1/behavior/bugs/1322.zig | 4 +- test/stage1/behavior/bugs/1381.zig | 2 +- test/stage1/behavior/bugs/1421.zig | 4 +- test/stage1/behavior/bugs/1442.zig | 2 +- test/stage1/behavior/bugs/1486.zig | 6 +- test/stage1/behavior/bugs/394.zig | 4 +- test/stage1/behavior/bugs/655.zig | 4 +- test/stage1/behavior/bugs/656.zig | 4 +- test/stage1/behavior/bugs/726.zig | 6 +- test/stage1/behavior/bugs/920.zig | 2 +- test/stage1/behavior/byval_arg_var.zig | 2 +- test/stage1/behavior/cancel.zig | 14 +- test/stage1/behavior/cast.zig | 158 ++++---- test/stage1/behavior/const_slice_child.zig | 13 +- .../behavior/coroutine_await_struct.zig | 6 +- test/stage1/behavior/coroutines.zig | 36 +- test/stage1/behavior/defer.zig | 24 +- test/stage1/behavior/enum.zig | 74 ++-- test/stage1/behavior/enum_with_members.zig | 10 +- test/stage1/behavior/error.zig | 62 +-- test/stage1/behavior/eval.zig | 232 +++++------ test/stage1/behavior/field_parent_ptr.zig | 14 +- test/stage1/behavior/fn.zig | 38 +- .../behavior/fn_in_struct_in_comptime.zig | 4 +- test/stage1/behavior/for.zig | 10 +- test/stage1/behavior/generics.zig | 46 +-- test/stage1/behavior/if.zig | 4 +- test/stage1/behavior/import.zig | 6 +- .../behavior/incomplete_struct_param_tld.zig | 4 +- test/stage1/behavior/inttoptr.zig | 2 +- test/stage1/behavior/ir_block_deps.zig | 6 +- test/stage1/behavior/math.zig | 256 ++++++------ test/stage1/behavior/misc.zig | 268 ++++++------- .../index.zig | 6 +- test/stage1/behavior/new_stack_call.zig | 10 +- test/stage1/behavior/null.zig | 34 +- test/stage1/behavior/optional.zig | 28 +- test/stage1/behavior/pointers.zig | 24 +- test/stage1/behavior/popcount.zig | 10 +- test/stage1/behavior/ptrcast.zig | 8 +- test/stage1/behavior/pub_enum/index.zig | 6 +- ...ef_var_in_if_after_if_2nd_switch_prong.zig | 10 +- test/stage1/behavior/reflection.zig | 78 ++-- test/stage1/behavior/sizeof_and_typeof.zig | 60 +-- test/stage1/behavior/slice.zig | 16 +- test/stage1/behavior/struct.zig | 184 ++++----- .../struct_contains_null_ptr_itself.zig | 4 +- .../struct_contains_slice_of_itself.zig | 26 +- test/stage1/behavior/switch.zig | 66 ++-- .../stage1/behavior/switch_prong_err_enum.zig | 6 +- .../behavior/switch_prong_implicit_cast.zig | 4 +- test/stage1/behavior/this.zig | 8 +- test/stage1/behavior/truncate.zig | 4 +- test/stage1/behavior/try.zig | 10 +- test/stage1/behavior/type_info.zig | 182 ++++----- test/stage1/behavior/undefined.zig | 28 +- test/stage1/behavior/underscore.zig | 2 +- test/stage1/behavior/union.zig | 76 ++-- test/stage1/behavior/var_args.zig | 34 +- test/stage1/behavior/vector.zig | 8 +- test/stage1/behavior/void.zig | 8 +- test/stage1/behavior/while.zig | 44 +-- test/stage1/behavior/widening.zig | 8 +- test/stage1/c_abi/main.zig | 82 ++-- test/standalone/brace_expansion/main.zig | 9 +- test/standalone/issue_794/main.zig | 4 +- 239 files changed, 4084 insertions(+), 3938 deletions(-) create mode 100644 std/testing.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index d6bd8a6c2e..ed79f99901 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -658,6 +658,7 @@ set(ZIG_STD_FILES "special/test_runner.zig" "spinlock.zig" "statically_initialized_mutex.zig" + "testing.zig" "unicode.zig" "zig/ast.zig" "zig/index.zig" diff --git a/doc/docgen.zig b/doc/docgen.zig index 14e4700553..7aaf5ebdc7 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -4,7 +4,7 @@ const io = std.io; const os = std.os; const warn = std.debug.warn; const mem = std.mem; -const assert = std.debug.assert; +const testing = std.testing; const max_doc_file_size = 10 * 1024 * 1024; @@ -620,7 +620,7 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; const result = try termColor(std.debug.global_allocator, input_bytes); - assert(mem.eql(u8, result, "AgreenB")); + testing.expectEqualSlices(u8, "AgreenB", result)); } fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 { diff --git a/src-self-hosted/arg.zig b/src-self-hosted/arg.zig index 99e6ecc17a..7bbd233a75 100644 --- a/src-self-hosted/arg.zig +++ b/src-self-hosted/arg.zig @@ -1,5 +1,6 @@ const std = @import("std"); const debug = std.debug; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -272,21 +273,21 @@ test "parse arguments" { var args = try Args.parse(std.debug.global_allocator, spec1, cliargs); - debug.assert(args.present("help")); - debug.assert(!args.present("help2")); - debug.assert(!args.present("init")); + testing.expect(args.present("help")); + testing.expect(!args.present("help2")); + testing.expect(!args.present("init")); - debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig")); - debug.assert(mem.eql(u8, args.single("color").?, "on")); + testing.expect(mem.eql(u8, args.single("build-file").?, "build.zig")); + testing.expect(mem.eql(u8, args.single("color").?, "on")); const objects = args.many("object").?; - debug.assert(mem.eql(u8, objects[0], "obj1")); - debug.assert(mem.eql(u8, objects[1], "obj2")); + testing.expect(mem.eql(u8, objects[0], "obj1")); + testing.expect(mem.eql(u8, objects[1], "obj2")); - debug.assert(mem.eql(u8, args.single("library").?, "lib2")); + testing.expect(mem.eql(u8, args.single("library").?, "lib2")); const pos = args.positionals.toSliceConst(); - debug.assert(mem.eql(u8, pos[0], "build")); - debug.assert(mem.eql(u8, pos[1], "pos1")); - debug.assert(mem.eql(u8, pos[2], "pos2")); + testing.expect(mem.eql(u8, pos[0], "build")); + testing.expect(mem.eql(u8, pos[1], "pos1")); + testing.expect(mem.eql(u8, pos[2], "pos2")); } diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index de551cf7f7..4be6d53932 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -4,7 +4,7 @@ const builtin = @import("builtin"); const Target = @import("target.zig").Target; const Compilation = @import("compilation.zig").Compilation; const introspect = @import("introspect.zig"); -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; const errmsg = @import("errmsg.zig"); const ZigCompiler = @import("compilation.zig").ZigCompiler; @@ -210,7 +210,7 @@ pub const TestContext = struct { @panic("build incorrectly failed"); }, Compilation.Event.Fail => |msgs| { - assertOrPanic(msgs.len != 0); + testing.expect(msgs.len != 0); for (msgs) |msg| { if (mem.endsWith(u8, msg.realpath, path) and mem.eql(u8, msg.text, text)) { const span = msg.getSpan(); diff --git a/src/ir.cpp b/src/ir.cpp index 00d358552a..efda2b321b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17543,21 +17543,16 @@ 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, ZigType *type_entry, ConstExprValue **out) { +static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigType *type_entry, ConstExprValue **out) { Error err; assert(type_entry != nullptr); assert(!type_is_invalid(type_entry)); - if ((err = ensure_complete_type(ira->codegen, type_entry))) + if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) return err; - if (type_entry == ira->codegen->builtin_types.entry_global_error_set) { - zig_panic("TODO implement @typeInfo for global error set"); - } - ConstExprValue *result = nullptr; - switch (type_entry->id) - { + switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); case ZigTypeIdMetaType: @@ -17778,6 +17773,15 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE 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)) { + return ErrorSemanticAnalyzeFail; + } + if (type_is_global_error_set(type_entry)) { + ir_add_error_node(ira, source_node, + buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936")); + return ErrorSemanticAnalyzeFail; + } + uint32_t error_count = type_entry->data.error_set.err_count; ConstExprValue *error_array = create_const_vals(1); error_array->special = ConstValSpecialStatic; @@ -18103,7 +18107,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE { ZigType *fn_type = type_entry->data.bound_fn.fn_type; assert(fn_type->id == ZigTypeIdFn); - if ((err = ir_make_type_info_value(ira, fn_type, &result))) + if ((err = ir_make_type_info_value(ira, source_node, fn_type, &result))) return err; break; @@ -18128,7 +18132,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, type_entry, &payload))) + if ((err = ir_make_type_info_value(ira, instruction->base.source_node, type_entry, &payload))) return ira->codegen->invalid_instruction; IrInstruction *result = ir_const(ira, &instruction->base, result_type); diff --git a/std/array_list.zig b/std/array_list.zig index ddad9c989c..e2535d6393 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -1,7 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; -const assertError = debug.assertError; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -212,8 +212,8 @@ test "std.ArrayList.init" { var list = ArrayList(i32).init(allocator); defer list.deinit(); - assert(list.count() == 0); - assert(list.capacity() == 0); + testing.expect(list.count() == 0); + testing.expect(list.capacity() == 0); } test "std.ArrayList.basic" { @@ -224,7 +224,7 @@ test "std.ArrayList.basic" { defer list.deinit(); // setting on empty list is out of bounds - assertError(list.setOrError(0, 1), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.setOrError(0, 1)); { var i: usize = 0; @@ -236,44 +236,44 @@ test "std.ArrayList.basic" { { var i: usize = 0; while (i < 10) : (i += 1) { - assert(list.items[i] == @intCast(i32, i + 1)); + testing.expect(list.items[i] == @intCast(i32, i + 1)); } } for (list.toSlice()) |v, i| { - assert(v == @intCast(i32, i + 1)); + testing.expect(v == @intCast(i32, i + 1)); } for (list.toSliceConst()) |v, i| { - assert(v == @intCast(i32, i + 1)); + testing.expect(v == @intCast(i32, i + 1)); } - assert(list.pop() == 10); - assert(list.len == 9); + testing.expect(list.pop() == 10); + testing.expect(list.len == 9); list.appendSlice([]const i32{ 1, 2, 3, }) catch unreachable; - assert(list.len == 12); - assert(list.pop() == 3); - assert(list.pop() == 2); - assert(list.pop() == 1); - assert(list.len == 9); + testing.expect(list.len == 12); + testing.expect(list.pop() == 3); + testing.expect(list.pop() == 2); + testing.expect(list.pop() == 1); + testing.expect(list.len == 9); list.appendSlice([]const i32{}) catch unreachable; - assert(list.len == 9); + testing.expect(list.len == 9); // can only set on indices < self.len list.set(7, 33); list.set(8, 42); - assertError(list.setOrError(9, 99), error.OutOfBounds); - assertError(list.setOrError(10, 123), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.setOrError(9, 99)); + testing.expectError(error.OutOfBounds, list.setOrError(10, 123)); - assert(list.pop() == 42); - assert(list.pop() == 33); + testing.expect(list.pop() == 42); + testing.expect(list.pop() == 33); } test "std.ArrayList.swapRemove" { @@ -289,18 +289,18 @@ test "std.ArrayList.swapRemove" { try list.append(7); //remove from middle - assert(list.swapRemove(3) == 4); - assert(list.at(3) == 7); - assert(list.len == 6); + testing.expect(list.swapRemove(3) == 4); + testing.expect(list.at(3) == 7); + testing.expect(list.len == 6); //remove from end - assert(list.swapRemove(5) == 6); - assert(list.len == 5); + testing.expect(list.swapRemove(5) == 6); + testing.expect(list.len == 5); //remove from front - assert(list.swapRemove(0) == 1); - assert(list.at(0) == 5); - assert(list.len == 4); + testing.expect(list.swapRemove(0) == 1); + testing.expect(list.at(0) == 5); + testing.expect(list.len == 4); } test "std.ArrayList.swapRemoveOrError" { @@ -308,27 +308,27 @@ test "std.ArrayList.swapRemoveOrError" { defer list.deinit(); // Test just after initialization - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test after adding one item and remote it try list.append(1); - assert((try list.swapRemoveOrError(0)) == 1); - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expect((try list.swapRemoveOrError(0)) == 1); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test after adding two items and remote both try list.append(1); try list.append(2); - assert((try list.swapRemoveOrError(1)) == 2); - assert((try list.swapRemoveOrError(0)) == 1); - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expect((try list.swapRemoveOrError(1)) == 2); + testing.expect((try list.swapRemoveOrError(0)) == 1); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test out of bounds with one item try list.append(1); - assertError(list.swapRemoveOrError(1), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(1)); // Test out of bounds with two items try list.append(2); - assertError(list.swapRemoveOrError(2), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(2)); } test "std.ArrayList.iterator" { @@ -342,22 +342,22 @@ test "std.ArrayList.iterator" { var count: i32 = 0; var it = list.iterator(); while (it.next()) |next| { - assert(next == count + 1); + testing.expect(next == count + 1); count += 1; } - assert(count == 3); - assert(it.next() == null); + testing.expect(count == 3); + testing.expect(it.next() == null); it.reset(); count = 0; while (it.next()) |next| { - assert(next == count + 1); + testing.expect(next == count + 1); count += 1; if (count == 2) break; } it.reset(); - assert(it.next().? == 1); + testing.expect(it.next().? == 1); } test "std.ArrayList.insert" { @@ -368,10 +368,10 @@ test "std.ArrayList.insert" { try list.append(2); try list.append(3); try list.insert(0, 5); - assert(list.items[0] == 5); - assert(list.items[1] == 1); - assert(list.items[2] == 2); - assert(list.items[3] == 3); + testing.expect(list.items[0] == 5); + testing.expect(list.items[1] == 1); + testing.expect(list.items[2] == 2); + testing.expect(list.items[3] == 3); } test "std.ArrayList.insertSlice" { @@ -386,17 +386,17 @@ test "std.ArrayList.insertSlice" { 9, 8, }); - assert(list.items[0] == 1); - assert(list.items[1] == 9); - assert(list.items[2] == 8); - assert(list.items[3] == 2); - assert(list.items[4] == 3); - assert(list.items[5] == 4); + testing.expect(list.items[0] == 1); + testing.expect(list.items[1] == 9); + testing.expect(list.items[2] == 8); + testing.expect(list.items[3] == 2); + testing.expect(list.items[4] == 3); + testing.expect(list.items[5] == 4); const items = []const i32{1}; try list.insertSlice(0, items[0..0]); - assert(list.len == 6); - assert(list.items[0] == 1); + testing.expect(list.len == 6); + testing.expect(list.items[0] == 1); } const Item = struct { @@ -407,5 +407,5 @@ 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) } ); - assert(root.sub_items.items[0].integer == 42); + testing.expect(root.sub_items.items[0].integer == 42); } diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 183c434dc5..bdc86c0981 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; const assert = std.debug.assert; +const expect = std.testing.expect; /// Many producer, many consumer, non-allocating, thread-safe. /// Uses a mutex to protect access. @@ -174,14 +175,14 @@ test "std.atomic.Queue" { { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startPuts(&context) == 0); + expect(startPuts(&context) == 0); } } context.puts_done = 1; { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startGets(&context) == 0); + expect(startGets(&context) == 0); } } } else { @@ -264,7 +265,7 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_1); - assert(queue.get().?.data == 0); + expect(queue.get().?.data == 0); var node_2 = Queue(i32).Node{ .data = 2, @@ -280,9 +281,9 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_3); - assert(queue.get().?.data == 1); + expect(queue.get().?.data == 1); - assert(queue.get().?.data == 2); + expect(queue.get().?.data == 2); var node_4 = Queue(i32).Node{ .data = 4, @@ -291,12 +292,12 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_4); - assert(queue.get().?.data == 3); + expect(queue.get().?.data == 3); node_3.next = null; - assert(queue.get().?.data == 4); + expect(queue.get().?.data == 4); - assert(queue.get() == null); + expect(queue.get() == null); } test "std.atomic.Queue dump" { @@ -311,7 +312,7 @@ test "std.atomic.Queue dump" { // Test empty stream sos.reset(); try queue.dumpToStream(SliceOutStream.Error, &sos.stream); - assert(mem.eql(u8, buffer[0..sos.pos], + expect(mem.eql(u8, buffer[0..sos.pos], \\head: (null) \\tail: (null) \\ @@ -335,7 +336,7 @@ test "std.atomic.Queue dump" { \\ (null) \\ , @ptrToInt(queue.head), @ptrToInt(queue.tail)); - assert(mem.eql(u8, buffer[0..sos.pos], expected)); + expect(mem.eql(u8, buffer[0..sos.pos], expected)); // Test a stream with two elements var node_1 = Queue(i32).Node{ @@ -356,5 +357,5 @@ test "std.atomic.Queue dump" { \\ (null) \\ , @ptrToInt(queue.head), @ptrToInt(queue.head.?.next), @ptrToInt(queue.tail)); - assert(mem.eql(u8, buffer[0..sos.pos], expected)); + expect(mem.eql(u8, buffer[0..sos.pos], expected)); } diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 503fa0c0ce..4d0d5075e0 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -1,6 +1,7 @@ const assert = std.debug.assert; const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; +const expect = std.testing.expect; /// Many reader, many writer, non-allocating, thread-safe /// Uses a spinlock to protect push() and pop() @@ -108,14 +109,14 @@ test "std.atomic.stack" { { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startPuts(&context) == 0); + expect(startPuts(&context) == 0); } } context.puts_done = 1; { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startGets(&context) == 0); + expect(startGets(&context) == 0); } } } else { diff --git a/std/base64.zig b/std/base64.zig index bc0bdb1bd3..cfe8ea95f8 100644 --- a/std/base64.zig +++ b/std/base64.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -394,7 +395,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)]; standard_encoder.encode(encoded, expected_decoded); - assert(mem.eql(u8, encoded, expected_encoded)); + testing.expectEqualSlices(u8, expected_encoded, encoded); } // Base64Decoder @@ -402,7 +403,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..try standard_decoder.calcSize(expected_encoded)]; try standard_decoder.decode(decoded, expected_encoded); - assert(mem.eql(u8, decoded, expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded); } // Base64DecoderWithIgnore @@ -411,8 +412,8 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)]; var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded); - assert(written <= decoded.len); - assert(mem.eql(u8, decoded[0..written], expected_decoded)); + testing.expect(written <= decoded.len); + testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); } // Base64DecoderUnsafe @@ -420,7 +421,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)]; standard_decoder_unsafe.decode(decoded, expected_encoded); - assert(mem.eql(u8, decoded, expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded); } } @@ -429,7 +430,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi var buffer: [0x100]u8 = undefined; var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)]; var written = try standard_decoder_ignore_space.decode(decoded, encoded); - assert(mem.eql(u8, decoded[0..written], expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); } fn testError(encoded: []const u8, expected_err: anyerror) !void { diff --git a/std/buf_map.zig b/std/buf_map.zig index 6de0d20cdb..f8d3d5e04d 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const HashMap = std.HashMap; const mem = std.mem; const Allocator = mem.Allocator; -const assert = std.debug.assert; +const testing = std.testing; /// BufMap copies keys and values before they go into the map, and /// frees them when they get removed. @@ -90,17 +90,17 @@ test "BufMap" { defer bufmap.deinit(); try bufmap.set("x", "1"); - assert(mem.eql(u8, bufmap.get("x").?, "1")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "1")); + testing.expect(1 == bufmap.count()); try bufmap.set("x", "2"); - assert(mem.eql(u8, bufmap.get("x").?, "2")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "2")); + testing.expect(1 == bufmap.count()); try bufmap.set("x", "3"); - assert(mem.eql(u8, bufmap.get("x").?, "3")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "3")); + testing.expect(1 == bufmap.count()); bufmap.delete("x"); - assert(0 == bufmap.count()); + testing.expect(0 == bufmap.count()); } diff --git a/std/buf_set.zig b/std/buf_set.zig index ab2d8e7c34..7ccd94c179 100644 --- a/std/buf_set.zig +++ b/std/buf_set.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const HashMap = @import("hash_map.zig").HashMap; const mem = @import("mem.zig"); const Allocator = mem.Allocator; -const assert = std.debug.assert; +const testing = std.testing; pub const BufSet = struct { hash_map: BufSetHashMap, @@ -68,9 +68,9 @@ test "BufSet" { defer bufset.deinit(); try bufset.put("x"); - assert(bufset.count() == 1); + testing.expect(bufset.count() == 1); bufset.delete("x"); - assert(bufset.count() == 0); + testing.expect(bufset.count() == 0); try bufset.put("x"); try bufset.put("y"); diff --git a/std/buffer.zig b/std/buffer.zig index 2b71c26749..371655f1e5 100644 --- a/std/buffer.zig +++ b/std/buffer.zig @@ -3,6 +3,7 @@ const debug = std.debug; const mem = std.mem; const Allocator = mem.Allocator; const assert = debug.assert; +const testing = std.testing; const ArrayList = std.ArrayList; /// A buffer that allocates memory and maintains a null byte at the end. @@ -141,19 +142,19 @@ test "simple Buffer" { const cstr = @import("cstr.zig"); var buf = try Buffer.init(debug.global_allocator, ""); - assert(buf.len() == 0); + testing.expect(buf.len() == 0); try buf.append("hello"); try buf.append(" "); try buf.append("world"); - assert(buf.eql("hello world")); - assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst())); + testing.expect(buf.eql("hello world")); + testing.expect(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst())); var buf2 = try Buffer.initFromBuffer(buf); - assert(buf.eql(buf2.toSliceConst())); + testing.expect(buf.eql(buf2.toSliceConst())); - assert(buf.startsWith("hell")); - assert(buf.endsWith("orld")); + testing.expect(buf.startsWith("hell")); + testing.expect(buf.endsWith("orld")); try buf2.resize(4); - assert(buf.startsWith(buf2.toSlice())); + testing.expect(buf.startsWith(buf2.toSlice())); } diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 5ec1e79756..d964f4c03d 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -4,6 +4,7 @@ const std = @import("../index.zig"); const mem = std.mem; const endian = std.endian; const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -216,12 +217,12 @@ test "crypto.chacha20 test vector sunscreen" { }; chaCha20IETF(result[0..], input[0..], 1, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); // Chacha20 is self-reversing. var plaintext: [114]u8 = undefined; chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); - assert(mem.compare(u8, input, plaintext) == mem.Compare.Equal); + testing.expect(mem.compare(u8, input, plaintext) == mem.Compare.Equal); } // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 @@ -256,7 +257,7 @@ test "crypto.chacha20 test vector 1" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 2" { @@ -290,7 +291,7 @@ test "crypto.chacha20 test vector 2" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 3" { @@ -324,7 +325,7 @@ test "crypto.chacha20 test vector 3" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 1 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 4" { @@ -358,7 +359,7 @@ test "crypto.chacha20 test vector 4" { const nonce = []u8{ 1, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 5" { @@ -430,5 +431,5 @@ test "crypto.chacha20 test vector 5" { }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index 0d7a4d672d..64adb17c45 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -230,5 +230,5 @@ test "poly1305 rfc7439 vector1" { var mac: [16]u8 = undefined; Poly1305.create(mac[0..], msg, key); - std.debug.assert(std.mem.eql(u8, mac, expected_mac)); + std.testing.expectEqualSlices(u8, expected_mac, mac); } diff --git a/std/crypto/test.zig b/std/crypto/test.zig index 3fa24272e5..258cdf7320 100644 --- a/std/crypto/test.zig +++ b/std/crypto/test.zig @@ -1,6 +1,7 @@ -const debug = @import("../debug/index.zig"); -const mem = @import("../mem.zig"); -const fmt = @import("../fmt/index.zig"); +const std = @import("../index.zig"); +const testing = std.testing; +const mem = std.mem; +const fmt = std.fmt; // Hash using the specified hasher `H` asserting `expected == H(input)`. pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) void { @@ -17,5 +18,5 @@ pub fn assertEqual(comptime expected: []const u8, input: []const u8) void { r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable; } - debug.assert(mem.eql(u8, expected_bytes, input)); + testing.expectEqualSlices(u8, expected_bytes, input); } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index daccb56808..9349569f97 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -581,8 +581,8 @@ test "x25519 public key calculation from secret key" { var pk_calculated: [32]u8 = undefined; try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50"); - std.debug.assert(X25519.createPublicKey(pk_calculated[0..], sk)); - std.debug.assert(std.mem.eql(u8, pk_calculated, pk_expected)); + std.testing.expect(X25519.createPublicKey(pk_calculated[0..], sk)); + std.testing.expect(std.mem.eql(u8, pk_calculated, pk_expected)); } test "x25519 rfc7748 vector1" { @@ -593,8 +593,8 @@ test "x25519 rfc7748 vector1" { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], secret_key, public_key)); - std.debug.assert(std.mem.eql(u8, output, expected_output)); + std.testing.expect(X25519.create(output[0..], secret_key, public_key)); + std.testing.expect(std.mem.eql(u8, output, expected_output)); } test "x25519 rfc7748 vector2" { @@ -605,8 +605,8 @@ test "x25519 rfc7748 vector2" { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], secret_key, public_key)); - std.debug.assert(std.mem.eql(u8, output, expected_output)); + std.testing.expect(X25519.create(output[0..], secret_key, public_key)); + std.testing.expect(std.mem.eql(u8, output, expected_output)); } test "x25519 rfc7748 one iteration" { @@ -619,13 +619,13 @@ test "x25519 rfc7748 one iteration" { var i: usize = 0; while (i < 1) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } test "x25519 rfc7748 1,000 iterations" { @@ -643,13 +643,13 @@ test "x25519 rfc7748 1,000 iterations" { var i: usize = 0; while (i < 1000) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } test "x25519 rfc7748 1,000,000 iterations" { @@ -666,11 +666,11 @@ test "x25519 rfc7748 1,000,000 iterations" { var i: usize = 0; while (i < 1000000) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } diff --git a/std/cstr.zig b/std/cstr.zig index a8aaf21279..abd2eac48f 100644 --- a/std/cstr.zig +++ b/std/cstr.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const debug = std.debug; const mem = std.mem; -const assert = debug.assert; +const testing = std.testing; pub const line_sep = switch (builtin.os) { builtin.Os.windows => "\r\n", @@ -42,8 +42,8 @@ test "cstr fns" { } fn testCStrFnsImpl() void { - assert(cmp(c"aoeu", c"aoez") == -1); - assert(len(c"123456789") == 9); + testing.expect(cmp(c"aoeu", c"aoez") == -1); + testing.expect(len(c"123456789") == 9); } /// Returns a mutable slice with 1 more byte of length which is a null byte. diff --git a/std/debug/index.zig b/std/debug/index.zig index a1e2747df5..7e5be9acef 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -107,37 +107,15 @@ pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { /// 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 can be -/// optimized away. +/// 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) { - // In ReleaseFast test mode, we still want assert(false) to crash, so - // we insert an explicit call to @panic instead of unreachable. - // TODO we should use `assertOrPanic` in tests and remove this logic. - if (builtin.is_test) { - @panic("assertion failure"); - } else { - unreachable; // assertion failure - } - } -} - -/// TODO: add `==` operator for `error_union == error_set`, and then -/// remove this function -pub fn assertError(value: var, expected_error: anyerror) void { - if (value) { - @panic("expected error"); - } else |actual_error| { - assert(actual_error == expected_error); - } -} - -/// Call this function when you want to panic if the condition is not true. -/// If `ok` is `false`, this function will panic in every release mode. -pub fn assertOrPanic(ok: bool) void { - if (!ok) { - @panic("assertion failure"); - } + if (!ok) unreachable; // assertion failure } pub fn panic(comptime format: []const u8, args: ...) noreturn { diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 4d19951318..66026b1f29 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -6,6 +6,7 @@ const mem = std.mem; const cstr = std.cstr; const os = std.os; const assert = std.debug.assert; +const testing = std.testing; const elf = std.elf; const linux = os.linux; const windows = os.windows; @@ -206,7 +207,7 @@ test "dynamic_library" { }; const dynlib = DynLib.open(std.debug.global_allocator, libname) catch |err| { - assert(err == error.FileNotFound); + testing.expect(err == error.FileNotFound); return; }; @panic("Expected error from function"); diff --git a/std/event/channel.zig b/std/event/channel.zig index f8cdae6208..4af9bf612b 100644 --- a/std/event/channel.zig +++ b/std/event/channel.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; const Loop = std.event.Loop; @@ -350,19 +351,19 @@ async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void { const value1_promise = try async channel.get(); const value1 = await value1_promise; - assert(value1 == 1234); + testing.expect(value1 == 1234); const value2_promise = try async channel.get(); const value2 = await value2_promise; - assert(value2 == 4567); + testing.expect(value2 == 4567); const value3_promise = try async channel.getOrNull(); const value3 = await value3_promise; - assert(value3 == null); + testing.expect(value3 == null); const last_put = try async testPut(channel, 4444); const value4 = await try async channel.getOrNull(); - assert(value4.? == 4444); + testing.expect(value4.? == 4444); await last_put; } diff --git a/std/event/fs.zig b/std/event/fs.zig index fd0fe434cb..0e7482ec60 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -2,6 +2,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const event = std.event; const assert = std.debug.assert; +const testing = std.testing; const os = std.os; const mem = std.mem; const posix = os.posix; @@ -1349,13 +1350,13 @@ async fn testFsWatch(loop: *Loop) !void { try await try async writeFile(loop, file_path, contents); const read_contents = try await try async readFile(loop, file_path, 1024 * 1024); - assert(mem.eql(u8, read_contents, contents)); + testing.expectEqualSlices(u8, contents, read_contents); // now watch the file var watch = try Watch(void).create(loop, 0); defer watch.destroy(); - assert((try await try async watch.addFile(file_path, {})) == null); + testing.expect((try await try async watch.addFile(file_path, {})) == null); const ev = try async watch.channel.get(); var ev_consumed = false; @@ -1375,10 +1376,10 @@ async fn testFsWatch(loop: *Loop) !void { WatchEventId.Delete => @panic("wrong event"), } const contents_updated = try await try async readFile(loop, file_path, 1024 * 1024); - assert(mem.eql(u8, contents_updated, + testing.expectEqualSlices(u8, \\line 1 \\lorem ipsum - )); + , contents_updated); // TODO test deleting the file and then re-adding it. we should get events for both } diff --git a/std/event/future.zig b/std/event/future.zig index 55ed01046d..66acac5ad7 100644 --- a/std/event/future.zig +++ b/std/event/future.zig @@ -1,5 +1,6 @@ const std = @import("../index.zig"); const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -114,7 +115,7 @@ async fn testFuture(loop: *Loop) void { const result = (await a) + (await b); cancel c; - assert(result == 12); + testing.expect(result == 12); } async fn waitOnFuture(future: *Future(i32)) i32 { diff --git a/std/event/group.zig b/std/event/group.zig index 7f6b5d953b..25e79640cb 100644 --- a/std/event/group.zig +++ b/std/event/group.zig @@ -4,7 +4,7 @@ const Lock = std.event.Lock; const Loop = std.event.Loop; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; -const assert = std.debug.assert; +const testing = std.testing; /// ReturnType must be `void` or `E!void` pub fn Group(comptime ReturnType: type) type { @@ -146,12 +146,12 @@ async fn testGroup(loop: *Loop) void { group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory"); group.call(increaseByTen, &count) catch @panic("memory"); await (async group.wait() catch @panic("memory")); - assert(count == 11); + testing.expect(count == 11); var another = Group(anyerror!void).init(loop); another.add(async somethingElse() catch @panic("memory")) catch @panic("memory"); another.call(doSomethingThatFails) catch @panic("memory"); - std.debug.assertError(await (async another.wait() catch @panic("memory")), error.ItBroke); + testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory"))); } async fn sleepALittle(count: *usize) void { diff --git a/std/event/lock.zig b/std/event/lock.zig index 01978e1909..d6a246cee5 100644 --- a/std/event/lock.zig +++ b/std/event/lock.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -141,7 +142,7 @@ test "std.event.Lock" { defer cancel handle; loop.run(); - assert(mem.eql(i32, shared_test_data, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len)); + testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data); } async fn testLock(loop: *Loop, lock: *Lock) void { diff --git a/std/event/loop.zig b/std/event/loop.zig index d5228db604..b92bf41982 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -896,7 +897,7 @@ test "std.event.Loop - call" { loop.run(); - assert(did_it); + testing.expect(did_it); } async fn testEventLoop() i32 { @@ -905,6 +906,6 @@ async fn testEventLoop() i32 { async fn testEventLoop2(h: promise->i32, did_it: *bool) void { const value = await h; - assert(value == 1234); + testing.expect(value == 1234); did_it.* = true; } diff --git a/std/event/net.zig b/std/event/net.zig index 9dac6aa566..48461c3d81 100644 --- a/std/event/net.zig +++ b/std/event/net.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); -const assert = std.debug.assert; +const testing = std.testing; const event = std.event; const mem = std.mem; const os = std.os; @@ -326,7 +326,7 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv var buf: [512]u8 = undefined; const amt_read = try socket_file.read(buf[0..]); const msg = buf[0..amt_read]; - assert(mem.eql(u8, msg, "hello from server\n")); + testing.expect(mem.eql(u8, msg, "hello from server\n")); server.close(); } diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig index f272ac71ea..26ccd12b73 100644 --- a/std/event/rwlock.zig +++ b/std/event/rwlock.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -231,7 +232,7 @@ test "std.event.RwLock" { loop.run(); const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len; - assert(mem.eql(i32, shared_test_data, expected_result)); + testing.expectEqualSlices(i32, expected_result, shared_test_data); } async fn testLock(loop: *Loop, lock: *RwLock) void { @@ -293,7 +294,7 @@ async fn readRunner(lock: *RwLock) void { const handle = await lock_promise; defer handle.release(); - assert(shared_test_index == 0); - assert(shared_test_data[i] == @intCast(i32, shared_count)); + testing.expect(shared_test_index == 0); + testing.expect(shared_test_data[i] == @intCast(i32, shared_count)); } } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 6097a12c23..05b028112f 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -2,7 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const debug = std.debug; const assert = debug.assert; -const assertError = debug.assertError; +const testing = std.testing; const mem = std.mem; const builtin = @import("builtin"); const errol = @import("errol/index.zig"); @@ -588,7 +588,7 @@ pub fn formatFloatDecimal( } // Remaining fractional portion, zero-padding if insufficient. - debug.assert(precision >= printed); + 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; @@ -798,13 +798,13 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T { } test "fmt.parseInt" { - assert((parseInt(i32, "-10", 10) catch unreachable) == -10); - assert((parseInt(i32, "+10", 10) catch unreachable) == 10); - assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); - assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); - assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); - assert((parseInt(u8, "255", 10) catch unreachable) == 255); - assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); + 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{ @@ -829,30 +829,30 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned } test "parseUnsigned" { - assert((try parseUnsigned(u16, "050124", 10)) == 50124); - assert((try parseUnsigned(u16, "65535", 10)) == 65535); - assertError(parseUnsigned(u16, "65536", 10), error.Overflow); + testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); + testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); + testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); - assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); - assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow); + testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); + testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); - assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); + testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); - assert((try parseUnsigned(u7, "1", 10)) == 1); - assert((try parseUnsigned(u7, "1000", 2)) == 8); + testing.expect((try parseUnsigned(u7, "1", 10)) == 1); + testing.expect((try parseUnsigned(u7, "1000", 2)) == 8); - assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter); - assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter); + testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); + testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); - assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); + testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); // these numbers should fit even though the radix itself doesn't fit in the destination type - assert((try parseUnsigned(u1, "0", 10)) == 0); - assert((try parseUnsigned(u1, "1", 10)) == 1); - assertError(parseUnsigned(u1, "2", 10), error.Overflow); - assert((try parseUnsigned(u1, "001", 16)) == 1); - assert((try parseUnsigned(u2, "3", 16)) == 3); - assertError(parseUnsigned(u2, "4", 16), error.Overflow); + 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 fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { @@ -910,19 +910,19 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) { test "buf print int" { var buffer: [max_int_digits]u8 = undefined; const buf = buffer[0..]; - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E")); + 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")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234")); + 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")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42")); + 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 { @@ -939,7 +939,7 @@ test "parse u64 digit too big" { test "parse unsigned comptime" { comptime { - assert((try parseUnsigned(usize, "2", 10)) == 2); + testing.expect((try parseUnsigned(usize, "2", 10)) == 2); } } @@ -977,17 +977,17 @@ test "fmt.format" { var context = BufPrintContext{ .remaining = buf1[0..] }; try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite); var res = buf1[0 .. buf1.len - context.remaining.len]; - assert(mem.eql(u8, res, "1234")); + 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]; - assert(mem.eql(u8, res, "a")); + 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]; - assert(mem.eql(u8, res, "1100")); + testing.expect(mem.eql(u8, res, "1100")); } { const value: [3]u8 = "abc"; @@ -1053,19 +1053,19 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f32 = 1.34; const result = try bufPrint(buf1[0..], "f32: {e}\n", value); - assert(mem.eql(u8, result, "f32: 1.34000003e+00\n")); + 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); - assert(mem.eql(u8, result, "f32: 1.23400001e+01\n")); + 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); - assert(mem.eql(u8, result, "f64: -1.234e+11\n")); + testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n")); } { // This fails on release due to a minor rounding difference. @@ -1075,26 +1075,26 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = 9.999960e-40; const result = try bufPrint(buf1[0..], "f64: {e}\n", value); - assert(mem.eql(u8, result, "f64: 9.99996e-40\n")); + 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); - assert(mem.eql(u8, result, "f64: 1.40971e-42\n")); + 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); - assert(mem.eql(u8, result, "f64: 1.00000e-09\n")); + 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); - assert(mem.eql(u8, result, "f64: 7.81250e-03\n")); + 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. @@ -1102,47 +1102,47 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = @bitCast(f32, u32(1203982400)); const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); - assert(mem.eql(u8, result, "f64: 1.00001e+05\n")); + 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); - assert(mem.eql(u8, result, "f64: nan\n")); + testing.expect(mem.eql(u8, result, "f64: nan\n")); } if (builtin.arch != builtin.Arch.armv8) { // 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); - assert(mem.eql(u8, result, "f64: -nan\n")); + 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); - assert(mem.eql(u8, result, "f64: inf\n")); + 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); - assert(mem.eql(u8, result, "f64: -inf\n")); + 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); - assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n")); + 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); - assert(mem.eql(u8, result, "f32: 1.1\n")); + 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); - assert(mem.eql(u8, result, "f32: 1234.57\n")); + testing.expect(mem.eql(u8, result, "f32: 1234.57\n")); } { var buf1: [32]u8 = undefined; @@ -1150,92 +1150,92 @@ test "fmt.format" { 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 - assert(mem.eql(u8, result, "f32: -11.1234\n")); + 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); - assert(mem.eql(u8, result, "f32: 91.12345\n")); + 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); - assert(mem.eql(u8, result, "f64: 91.1234567890\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + 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); - assert(mem.eql(u8, result, "f64: 6\n")); + 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); - assert(mem.eql(u8, result, "f64: 10.0\n")); + 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); - assert(mem.eql(u8, result, "f64: 1.000\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00030000\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00001\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.00001\n")); + 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); - assert(mem.eql(u8, result, "f64: 0.10000\n")); + 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); - assert(mem.eql(u8, result, "f64: 1.00000\n")); + 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); - assert(mem.eql(u8, result, "f64: 10.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 10.00000\n")); } // libc differences { @@ -1245,7 +1245,7 @@ test "fmt.format" { // 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); - assert(mem.eql(u8, result, "f64: 0.01563\n")); + testing.expect(mem.eql(u8, result, "f64: 0.01563\n")); } // std-windows-x86_64-Debug-bare test case fails { @@ -1255,7 +1255,7 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(1518338049))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n")); } //custom type format { @@ -1336,10 +1336,10 @@ test "fmt.format" { var buf: [100]u8 = undefined; const uu_result = try bufPrint(buf[0..], "{}", uu_inst); - debug.assert(mem.eql(u8, uu_result[0..3], "UU@")); + testing.expect(mem.eql(u8, uu_result[0..3], "UU@")); const eu_result = try bufPrint(buf[0..], "{}", eu_inst); - debug.assert(mem.eql(u8, uu_result[0..3], "EU@")); + testing.expect(mem.eql(u8, uu_result[0..3], "EU@")); } //enum format { @@ -1398,11 +1398,11 @@ pub fn trim(buf: []const u8) []const u8 { } test "fmt.trim" { - assert(mem.eql(u8, "abc", trim("\n abc \t"))); - assert(mem.eql(u8, "", trim(" "))); - assert(mem.eql(u8, "", trim(""))); - assert(mem.eql(u8, "abc", trim(" abc"))); - assert(mem.eql(u8, "abc", trim("abc "))); + 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 { diff --git a/std/hash/adler.zig b/std/hash/adler.zig index 9c5966f89b..78f960367a 100644 --- a/std/hash/adler.zig +++ b/std/hash/adler.zig @@ -4,7 +4,7 @@ // https://github.com/madler/zlib/blob/master/adler32.c const std = @import("../index.zig"); -const debug = std.debug; +const testing = std.testing; pub const Adler32 = struct { const base = 65521; @@ -89,19 +89,19 @@ pub const Adler32 = struct { }; test "adler32 sanity" { - debug.assert(Adler32.hash("a") == 0x620062); - debug.assert(Adler32.hash("example") == 0xbc002ed); + testing.expect(Adler32.hash("a") == 0x620062); + testing.expect(Adler32.hash("example") == 0xbc002ed); } test "adler32 long" { const long1 = []u8{1} ** 1024; - debug.assert(Adler32.hash(long1[0..]) == 0x06780401); + testing.expect(Adler32.hash(long1[0..]) == 0x06780401); const long2 = []u8{1} ** 1025; - debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402); + testing.expect(Adler32.hash(long2[0..]) == 0x0a7a0402); } test "adler32 very long" { const long = []u8{1} ** 5553; - debug.assert(Adler32.hash(long[0..]) == 0x707f15b2); + testing.expect(Adler32.hash(long[0..]) == 0x707f15b2); } diff --git a/std/hash/crc.zig b/std/hash/crc.zig index c4bd92884a..9bea358bf1 100644 --- a/std/hash/crc.zig +++ b/std/hash/crc.zig @@ -7,6 +7,7 @@ const std = @import("../index.zig"); const debug = std.debug; +const testing = std.testing; pub const Polynomial = struct { const IEEE = 0xedb88320; @@ -101,17 +102,17 @@ pub fn Crc32WithPoly(comptime poly: u32) type { test "crc32 ieee" { const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE); - debug.assert(Crc32Ieee.hash("") == 0x00000000); - debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); - debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); + testing.expect(Crc32Ieee.hash("") == 0x00000000); + testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43); + testing.expect(Crc32Ieee.hash("abc") == 0x352441c2); } test "crc32 castagnoli" { const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli); - debug.assert(Crc32Castagnoli.hash("") == 0x00000000); - debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); - debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); + testing.expect(Crc32Castagnoli.hash("") == 0x00000000); + testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330); + testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); } // half-byte lookup table implementation. @@ -165,15 +166,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type { test "small crc32 ieee" { const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE); - debug.assert(Crc32Ieee.hash("") == 0x00000000); - debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); - debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); + testing.expect(Crc32Ieee.hash("") == 0x00000000); + testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43); + testing.expect(Crc32Ieee.hash("abc") == 0x352441c2); } test "small crc32 castagnoli" { const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli); - debug.assert(Crc32Castagnoli.hash("") == 0x00000000); - debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); - debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); + testing.expect(Crc32Castagnoli.hash("") == 0x00000000); + testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330); + testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); } diff --git a/std/hash/fnv.zig b/std/hash/fnv.zig index 9bb18f14b3..6876b636f6 100644 --- a/std/hash/fnv.zig +++ b/std/hash/fnv.zig @@ -5,7 +5,7 @@ // https://tools.ietf.org/html/draft-eastlake-fnv-14 const std = @import("../index.zig"); -const debug = std.debug; +const testing = std.testing; pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5); pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325); @@ -41,18 +41,18 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type { } test "fnv1a-32" { - debug.assert(Fnv1a_32.hash("") == 0x811c9dc5); - debug.assert(Fnv1a_32.hash("a") == 0xe40c292c); - debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968); + testing.expect(Fnv1a_32.hash("") == 0x811c9dc5); + testing.expect(Fnv1a_32.hash("a") == 0xe40c292c); + testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968); } test "fnv1a-64" { - debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325); - debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); - debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); + testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325); + testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); + testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); } test "fnv1a-128" { - debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); - debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); + testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); + testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); } diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index ee26950272..c9a6128d35 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -6,7 +6,8 @@ // https://131002.net/siphash/ const std = @import("../index.zig"); -const debug = std.debug; +const assert = std.debug.assert; +const testing = std.testing; const math = std.math; const mem = std.mem; @@ -21,8 +22,8 @@ pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type { } fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { - debug.assert(T == u64 or T == u128); - debug.assert(c_rounds > 0 and d_rounds > 0); + assert(T == u64 or T == u128); + assert(c_rounds > 0 and d_rounds > 0); return struct { const Self = @This(); @@ -40,7 +41,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) msg_len: u8, pub fn init(key: []const u8) Self { - debug.assert(key.len >= 16); + assert(key.len >= 16); const k0 = mem.readIntSliceLittle(u64, key[0..8]); const k1 = mem.readIntSliceLittle(u64, key[8..16]); @@ -119,7 +120,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) } fn round(d: *Self, b: []const u8) void { - debug.assert(b.len == 8); + assert(b.len == 8); const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; @@ -236,7 +237,7 @@ test "siphash64-2-4 sanity" { buffer[i] = @intCast(u8, i); const expected = mem.readIntLittle(u64, &vector); - debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); + testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); } } @@ -315,6 +316,6 @@ test "siphash128-2-4 sanity" { buffer[i] = @intCast(u8, i); const expected = mem.readIntLittle(u128, &vector); - debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); + testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/hash_map.zig b/std/hash_map.zig index a63a549814..716f04ff34 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const math = std.math; const mem = std.mem; const Allocator = mem.Allocator; @@ -342,37 +343,37 @@ test "basic hash map usage" { var map = AutoHashMap(i32, i32).init(&direct_allocator.allocator); defer map.deinit(); - assert((try map.put(1, 11)) == null); - assert((try map.put(2, 22)) == null); - assert((try map.put(3, 33)) == null); - assert((try map.put(4, 44)) == null); - assert((try map.put(5, 55)) == null); + testing.expect((try map.put(1, 11)) == null); + testing.expect((try map.put(2, 22)) == null); + testing.expect((try map.put(3, 33)) == null); + testing.expect((try map.put(4, 44)) == null); + testing.expect((try map.put(5, 55)) == null); - assert((try map.put(5, 66)).?.value == 55); - assert((try map.put(5, 55)).?.value == 66); + testing.expect((try map.put(5, 66)).?.value == 55); + testing.expect((try map.put(5, 55)).?.value == 66); const gop1 = try map.getOrPut(5); - assert(gop1.found_existing == true); - assert(gop1.kv.value == 55); + testing.expect(gop1.found_existing == true); + testing.expect(gop1.kv.value == 55); gop1.kv.value = 77; - assert(map.get(5).?.value == 77); + testing.expect(map.get(5).?.value == 77); const gop2 = try map.getOrPut(99); - assert(gop2.found_existing == false); + testing.expect(gop2.found_existing == false); gop2.kv.value = 42; - assert(map.get(99).?.value == 42); + testing.expect(map.get(99).?.value == 42); const gop3 = try map.getOrPutValue(5, 5); - assert(gop3.value == 77); + testing.expect(gop3.value == 77); const gop4 = try map.getOrPutValue(100, 41); - assert(gop4.value == 41); + testing.expect(gop4.value == 41); - assert(map.contains(2)); - assert(map.get(2).?.value == 22); + testing.expect(map.contains(2)); + testing.expect(map.get(2).?.value == 22); _ = map.remove(2); - assert(map.remove(2) == null); - assert(map.get(2) == null); + testing.expect(map.remove(2) == null); + testing.expect(map.get(2) == null); } test "iterator hash map" { @@ -382,9 +383,9 @@ test "iterator hash map" { var reset_map = AutoHashMap(i32, i32).init(&direct_allocator.allocator); defer reset_map.deinit(); - assert((try reset_map.put(1, 11)) == null); - assert((try reset_map.put(2, 22)) == null); - assert((try reset_map.put(3, 33)) == null); + testing.expect((try reset_map.put(1, 11)) == null); + testing.expect((try reset_map.put(2, 22)) == null); + testing.expect((try reset_map.put(3, 33)) == null); var keys = []i32{ 3, @@ -400,26 +401,26 @@ test "iterator hash map" { var it = reset_map.iterator(); var count: usize = 0; while (it.next()) |next| { - assert(next.key == keys[count]); - assert(next.value == values[count]); + testing.expect(next.key == keys[count]); + testing.expect(next.value == values[count]); count += 1; } - assert(count == 3); - assert(it.next() == null); + testing.expect(count == 3); + testing.expect(it.next() == null); it.reset(); count = 0; while (it.next()) |next| { - assert(next.key == keys[count]); - assert(next.value == values[count]); + testing.expect(next.key == keys[count]); + testing.expect(next.value == values[count]); count += 1; if (count == 2) break; } it.reset(); var entry = it.next().?; - assert(entry.key == keys[0]); - assert(entry.value == values[0]); + testing.expect(entry.key == keys[0]); + testing.expect(entry.value == values[0]); } pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) { diff --git a/std/heap.zig b/std/heap.zig index 8a5ebf134c..e7088150a8 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const os = std.os; const builtin = @import("builtin"); @@ -487,11 +488,11 @@ test "FixedBufferAllocator Reuse memory on realloc" { var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 5); - assert(slice0.len == 5); + testing.expect(slice0.len == 5); var slice1 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 10); - assert(slice1.ptr == slice0.ptr); - assert(slice1.len == 10); - debug.assertError(fixed_buffer_allocator.allocator.realloc(u8, slice1, 11), error.OutOfMemory); + testing.expect(slice1.ptr == slice0.ptr); + testing.expect(slice1.len == 10); + testing.expectError(error.OutOfMemory, fixed_buffer_allocator.allocator.realloc(u8, slice1, 11)); } // check that we don't re-use the memory if it's not the most recent block { @@ -502,10 +503,10 @@ test "FixedBufferAllocator Reuse memory on realloc" { slice0[1] = 2; var slice1 = try fixed_buffer_allocator.allocator.alloc(u8, 2); var slice2 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 4); - assert(slice0.ptr != slice2.ptr); - assert(slice1.ptr != slice2.ptr); - assert(slice2[0] == 1); - assert(slice2[1] == 2); + testing.expect(slice0.ptr != slice2.ptr); + testing.expect(slice1.ptr != slice2.ptr); + testing.expect(slice2[0] == 1); + testing.expect(slice2[1] == 2); } } @@ -519,28 +520,28 @@ test "ThreadSafeFixedBufferAllocator" { fn testAllocator(allocator: *mem.Allocator) !void { var slice = try allocator.alloc(*i32, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); for (slice) |*item, i| { item.* = try allocator.create(i32); item.*.* = @intCast(i32, i); } slice = try allocator.realloc(*i32, slice, 20000); - assert(slice.len == 20000); + testing.expect(slice.len == 20000); for (slice[0..100]) |item, i| { - assert(item.* == @intCast(i32, i)); + testing.expect(item.* == @intCast(i32, i)); allocator.destroy(item); } slice = try allocator.realloc(*i32, slice, 50); - assert(slice.len == 50); + testing.expect(slice.len == 50); slice = try allocator.realloc(*i32, slice, 25); - assert(slice.len == 25); + testing.expect(slice.len == 25); slice = try allocator.realloc(*i32, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); slice = try allocator.realloc(*i32, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); allocator.free(slice); } @@ -548,25 +549,25 @@ fn testAllocator(allocator: *mem.Allocator) !void { fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !void { // initial var slice = try allocator.alignedAlloc(u8, alignment, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // grow slice = try allocator.alignedRealloc(u8, alignment, slice, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); // shrink slice = try allocator.alignedRealloc(u8, alignment, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // go to zero slice = try allocator.alignedRealloc(u8, alignment, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); // realloc from zero slice = try allocator.alignedRealloc(u8, alignment, slice, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); // shrink with shrink slice = allocator.alignedShrink(u8, alignment, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // shrink to zero slice = allocator.alignedShrink(u8, alignment, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); } fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { @@ -581,19 +582,19 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask); var slice = try allocator.allocFn(allocator, 500, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 100, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 5000, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 10, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 20000, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); allocator.free(slice); } diff --git a/std/index.zig b/std/index.zig index 2a63244004..9d9b7ee8d6 100644 --- a/std/index.zig +++ b/std/index.zig @@ -31,6 +31,7 @@ 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"); @@ -41,11 +42,10 @@ 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"); -pub const lazyInit = @import("lazy_init.zig").lazyInit; - test "std" { // run tests from these _ = @import("array_list.zig"); @@ -60,7 +60,6 @@ test "std" { _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); - _ = @import("dynamic_library.zig"); _ = @import("base64.zig"); _ = @import("build.zig"); _ = @import("c/index.zig"); @@ -69,24 +68,26 @@ test "std" { _ = @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("meta/index.zig"); _ = @import("mem.zig"); + _ = @import("meta/index.zig"); _ = @import("net.zig"); - _ = @import("heap.zig"); _ = @import("os/index.zig"); - _ = @import("rand/index.zig"); _ = @import("pdb.zig"); + _ = @import("rand/index.zig"); _ = @import("sort.zig"); + _ = @import("testing.zig"); _ = @import("unicode.zig"); _ = @import("zig/index.zig"); - _ = @import("lazy_init.zig"); } diff --git a/std/io.zig b/std/io.zig index 81d90def6e..d7e8507f9b 100644 --- a/std/io.zig +++ b/std/io.zig @@ -13,6 +13,7 @@ const trait = meta.trait; const Buffer = std.Buffer; const fmt = std.fmt; const File = std.os.File; +const testing = std.testing; const is_posix = builtin.os != builtin.Os.windows; const is_windows = builtin.os == builtin.Os.windows; @@ -664,7 +665,7 @@ test "io.SliceOutStream" { const stream = &slice_stream.stream; try stream.print("{}{}!", "Hello", "World"); - debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); + testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten()); } var null_out_stream_state = NullOutStream.init(); @@ -726,7 +727,7 @@ test "io.CountingOutStream" { const bytes = "yay" ** 10000; stream.write(bytes) catch unreachable; - debug.assertOrPanic(counting_stream.bytes_written == bytes.len); + testing.expect(counting_stream.bytes_written == bytes.len); } pub fn BufferedOutStream(comptime Error: type) type { @@ -1014,10 +1015,10 @@ test "io.readLineFrom" { ); const stream = &mem_stream.stream; - debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); - debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); - debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); - debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); + testing.expectEqualSlices(u8, "Line 1", try readLineFrom(stream, &buf)); + testing.expectEqualSlices(u8, "Line 22", try readLineFrom(stream, &buf)); + testing.expectError(error.EndOfStream, readLineFrom(stream, &buf)); + testing.expectEqualSlices(u8, "Line 1Line 22Line 333", buf.toSlice()); } pub fn readLineSlice(slice: []u8) ![]u8 { @@ -1045,8 +1046,8 @@ test "io.readLineSliceFrom" { ); const stream = &mem_stream.stream; - debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); - debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); + testing.expectEqualSlices(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])); + testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..])); } /// Creates a deserializer that deserializes types from any stream. diff --git a/std/io_test.zig b/std/io_test.zig index 9a0687ec69..fb6e0ae7e9 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -3,8 +3,8 @@ const io = std.io; const meta = std.meta; const trait = std.trait; const DefaultPrng = std.rand.DefaultPrng; -const assert = std.debug.assert; -const assertError = std.debug.assertError; +const expect = std.testing.expect; +const expectError = std.testing.expectError; const mem = std.mem; const os = std.os; const builtin = @import("builtin"); @@ -35,7 +35,7 @@ test "write a file, read it, then delete it" { const file_size = try file.getEndPos(); const expected_file_size = "begin".len + data.len + "end".len; - assert(file_size == expected_file_size); + expect(file_size == expected_file_size); var file_in_stream = file.inStream(); var buf_stream = io.BufferedInStream(os.File.ReadError).init(&file_in_stream.stream); @@ -43,9 +43,9 @@ test "write a file, read it, then delete it" { const contents = try st.readAllAlloc(allocator, 2 * 1024); defer allocator.free(contents); - assert(mem.eql(u8, contents[0.."begin".len], "begin")); - assert(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); - assert(mem.eql(u8, contents[contents.len - "end".len ..], "end")); + expect(mem.eql(u8, contents[0.."begin".len], "begin")); + expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); + expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); } try os.deleteFile(tmp_file_name); } @@ -61,7 +61,7 @@ test "BufferOutStream" { const y: i32 = 1234; try buf_stream.print("x: {}\ny: {}\n", x, y); - assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n")); + expect(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n")); } test "SliceInStream" { @@ -71,15 +71,15 @@ test "SliceInStream" { var dest: [4]u8 = undefined; var read = try ss.stream.read(dest[0..4]); - assert(read == 4); - assert(mem.eql(u8, dest[0..4], bytes[0..4])); + expect(read == 4); + expect(mem.eql(u8, dest[0..4], bytes[0..4])); read = try ss.stream.read(dest[0..4]); - assert(read == 3); - assert(mem.eql(u8, dest[0..3], bytes[4..7])); + expect(read == 3); + expect(mem.eql(u8, dest[0..3], bytes[4..7])); read = try ss.stream.read(dest[0..4]); - assert(read == 0); + expect(read == 0); } test "PeekStream" { @@ -93,26 +93,26 @@ test "PeekStream" { ps.putBackByte(10); var read = try ps.stream.read(dest[0..4]); - assert(read == 4); - assert(dest[0] == 10); - assert(dest[1] == 9); - assert(mem.eql(u8, dest[2..4], bytes[0..2])); + expect(read == 4); + expect(dest[0] == 10); + expect(dest[1] == 9); + expect(mem.eql(u8, dest[2..4], bytes[0..2])); read = try ps.stream.read(dest[0..4]); - assert(read == 4); - assert(mem.eql(u8, dest[0..4], bytes[2..6])); + expect(read == 4); + expect(mem.eql(u8, dest[0..4], bytes[2..6])); read = try ps.stream.read(dest[0..4]); - assert(read == 2); - assert(mem.eql(u8, dest[0..2], bytes[6..8])); + expect(read == 2); + expect(mem.eql(u8, dest[0..2], bytes[6..8])); ps.putBackByte(11); ps.putBackByte(12); read = try ps.stream.read(dest[0..4]); - assert(read == 2); - assert(dest[0] == 12); - assert(dest[1] == 11); + expect(read == 2); + expect(dest[0] == 12); + expect(dest[1] == 11); } test "SliceOutStream" { @@ -120,19 +120,19 @@ test "SliceOutStream" { var ss = io.SliceOutStream.init(buffer[0..]); try ss.stream.write("Hello"); - assert(mem.eql(u8, ss.getWritten(), "Hello")); + expect(mem.eql(u8, ss.getWritten(), "Hello")); try ss.stream.write("world"); - assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + expect(mem.eql(u8, ss.getWritten(), "Helloworld")); - assertError(ss.stream.write("!"), error.OutOfSpace); - assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + expectError(error.OutOfSpace, ss.stream.write("!")); + expect(mem.eql(u8, ss.getWritten(), "Helloworld")); ss.reset(); - assert(ss.getWritten().len == 0); + expect(ss.getWritten().len == 0); - assertError(ss.stream.write("Hello world!"), error.OutOfSpace); - assert(mem.eql(u8, ss.getWritten(), "Hello worl")); + expectError(error.OutOfSpace, ss.stream.write("Hello world!")); + expect(mem.eql(u8, ss.getWritten(), "Hello worl")); } test "BitInStream" { @@ -145,66 +145,66 @@ test "BitInStream" { var out_bits: usize = undefined; - assert(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); mem_in_be.pos = 0; bit_stream_be.bit_count = 0; - assert(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); - assert(out_bits == 15); + expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); + expect(out_bits == 15); mem_in_be.pos = 0; bit_stream_be.bit_count = 0; - assert(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); - assert(out_bits == 16); + expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); + expect(out_bits == 16); _ = try bit_stream_be.readBits(u0, 0, &out_bits); - assert(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); - assert(out_bits == 0); - assertError(bit_stream_be.readBitsNoEof(u1, 1), error.EndOfStream); + expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); + expect(out_bits == 0); + expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1)); var mem_in_le = io.SliceInStream.init(mem_le[0..]); var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream); - assert(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); mem_in_le.pos = 0; bit_stream_le.bit_count = 0; - assert(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); - assert(out_bits == 15); + expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); + expect(out_bits == 15); mem_in_le.pos = 0; bit_stream_le.bit_count = 0; - assert(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); - assert(out_bits == 16); + expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); + expect(out_bits == 16); _ = try bit_stream_le.readBits(u0, 0, &out_bits); - assert(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); - assert(out_bits == 0); - assertError(bit_stream_le.readBitsNoEof(u1, 1), error.EndOfStream); + expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); + expect(out_bits == 0); + expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1)); } test "BitOutStream" { @@ -222,17 +222,17 @@ test "BitOutStream" { try bit_stream_be.writeBits(u9(5), 5); try bit_stream_be.writeBits(u1(1), 1); - assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); + expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); mem_out_be.pos = 0; try bit_stream_be.writeBits(u15(0b110011010000101), 15); try bit_stream_be.flushBits(); - assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); + expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); mem_out_be.pos = 0; try bit_stream_be.writeBits(u32(0b110011010000101), 16); - assert(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); + expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); try bit_stream_be.writeBits(u0(0), 0); @@ -246,16 +246,16 @@ test "BitOutStream" { try bit_stream_le.writeBits(u9(5), 5); try bit_stream_le.writeBits(u1(1), 1); - assert(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); + expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); mem_out_le.pos = 0; try bit_stream_le.writeBits(u15(0b110011010000101), 15); try bit_stream_le.flushBits(); - assert(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); + expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); mem_out_le.pos = 0; try bit_stream_le.writeBits(u32(0b1100110100001011), 16); - assert(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); + expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); try bit_stream_le.writeBits(u0(0), 0); } @@ -290,20 +290,20 @@ test "BitStreams with File Stream" { var out_bits: usize = undefined; - assert(1 == try bit_stream.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); - assertError(bit_stream.readBitsNoEof(u1, 1), error.EndOfStream); + expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); } try os.deleteFile(tmp_file_name); } @@ -345,8 +345,8 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const S = @IntType(true, i); const x = try deserializer.deserializeInt(U); const y = try deserializer.deserializeInt(S); - assert(x == U(i)); - if (i != 0) assert(y == S(-1)) else assert(y == 0); + expect(x == U(i)); + if (i != 0) expect(y == S(-1)) else expect(y == 0); } const u8_bit_count = comptime meta.bitCount(u8); @@ -356,7 +356,7 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0); const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; - assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); + expect(in.pos == if (is_packed) total_packed_bytes else total_bytes); //Verify that empty error set works with serializer. //deserializer is covered by SliceInStream @@ -408,14 +408,14 @@ fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian, const inf_check_f64 = try deserializer.deserialize(f64); //const nan_check_f128 = try deserializer.deserialize(f128); //const inf_check_f128 = try deserializer.deserialize(f128); - assert(std.math.isNan(nan_check_f16)); - assert(std.math.isInf(inf_check_f16)); - assert(std.math.isNan(nan_check_f32)); - assert(std.math.isInf(inf_check_f32)); - assert(std.math.isNan(nan_check_f64)); - assert(std.math.isInf(inf_check_f64)); - //assert(std.math.isNan(nan_check_f128)); - //assert(std.math.isInf(inf_check_f128)); + expect(std.math.isNan(nan_check_f16)); + expect(std.math.isInf(inf_check_f16)); + expect(std.math.isNan(nan_check_f32)); + expect(std.math.isInf(inf_check_f32)); + expect(std.math.isNan(nan_check_f64)); + expect(std.math.isInf(inf_check_f64)); + //expect(std.math.isNan(nan_check_f128)); + //expect(std.math.isInf(inf_check_f128)); } test "Serializer/Deserializer Int: Inf/NaN" { @@ -528,7 +528,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe try serializer.serialize(my_inst); const my_copy = try deserializer.deserialize(MyStruct); - assert(meta.eql(my_copy, my_inst)); + expect(meta.eql(my_copy, my_inst)); } test "Serializer/Deserializer generic" { @@ -565,11 +565,11 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); try serializer.serialize(u14(3)); - assertError(deserializer.deserialize(A), error.InvalidEnumTag); + expectError(error.InvalidEnumTag, deserializer.deserialize(A)); out.pos = 0; try serializer.serialize(u14(3)); try serializer.serialize(u14(88)); - assertError(deserializer.deserialize(C), error.InvalidEnumTag); + expectError(error.InvalidEnumTag, deserializer.deserialize(C)); } test "Deserializer bad data" { diff --git a/std/json.zig b/std/json.zig index 4d07d7b89d..d8f28560e5 100644 --- a/std/json.zig +++ b/std/json.zig @@ -4,6 +4,7 @@ const std = @import("index.zig"); const debug = std.debug; +const testing = std.testing; const mem = std.mem; const maxInt = std.math.maxInt; @@ -960,7 +961,7 @@ test "json.token" { checkNext(&p, Token.Id.ObjectEnd); checkNext(&p, Token.Id.ObjectEnd); - debug.assert((try p.next()) == null); + testing.expect((try p.next()) == null); } // Validate a JSON string. This does not limit number precision so a decoder may not necessarily @@ -981,7 +982,7 @@ pub fn validate(s: []const u8) bool { } test "json.validate" { - debug.assert(validate("{}")); + testing.expect(validate("{}")); } const Allocator = std.mem.Allocator; @@ -1378,20 +1379,20 @@ test "json.parser.dynamic" { var image = root.Object.get("Image").?.value; const width = image.Object.get("Width").?.value; - debug.assert(width.Integer == 800); + testing.expect(width.Integer == 800); const height = image.Object.get("Height").?.value; - debug.assert(height.Integer == 600); + testing.expect(height.Integer == 600); const title = image.Object.get("Title").?.value; - debug.assert(mem.eql(u8, title.String, "View from 15th Floor")); + testing.expect(mem.eql(u8, title.String, "View from 15th Floor")); const animated = image.Object.get("Animated").?.value; - debug.assert(animated.Bool == false); + testing.expect(animated.Bool == false); const array_of_object = image.Object.get("ArrayOfObject").?.value; - debug.assert(array_of_object.Array.len == 1); + testing.expect(array_of_object.Array.len == 1); const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; - debug.assert(mem.eql(u8, obj0.String, "m")); + testing.expect(mem.eql(u8, obj0.String, "m")); } diff --git a/std/json_test.zig b/std/json_test.zig index 9e19ec592a..edc50be8cb 100644 --- a/std/json_test.zig +++ b/std/json_test.zig @@ -6,15 +6,15 @@ const std = @import("index.zig"); fn ok(comptime s: []const u8) void { - std.debug.assert(std.json.validate(s)); + std.testing.expect(std.json.validate(s)); } fn err(comptime s: []const u8) void { - std.debug.assert(!std.json.validate(s)); + std.testing.expect(!std.json.validate(s)); } fn any(comptime s: []const u8) void { - std.debug.assert(true); + std.testing.expect(true); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/std/lazy_init.zig b/std/lazy_init.zig index f08c01e874..a09168786b 100644 --- a/std/lazy_init.zig +++ b/std/lazy_init.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -63,12 +64,12 @@ test "std.lazyInit" { global_number.resolve(); } if (global_number.get()) |x| { - assert(x.* == 1234); + testing.expect(x.* == 1234); } else { @panic("bad"); } if (global_number.get()) |x| { - assert(x.* == 1234); + testing.expect(x.* == 1234); } else { @panic("bad"); } @@ -80,6 +81,6 @@ test "std.lazyInit(void)" { if (global_void.get()) |_| @panic("bad") else { global_void.resolve(); } - assert(global_void.get() != null); - assert(global_void.get() != null); + testing.expect(global_void.get() != null); + testing.expect(global_void.get() != null); } diff --git a/std/linked_list.zig b/std/linked_list.zig index 7021cac707..86e5cd056e 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -246,7 +247,7 @@ test "basic linked list test" { var it = list.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -256,7 +257,7 @@ test "basic linked list test" { var it = list.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } @@ -265,9 +266,9 @@ test "basic linked list test" { var last = list.pop(); // {2, 3, 4} list.remove(three); // {2, 4} - assert(list.first.?.data == 2); - assert(list.last.?.data == 4); - assert(list.len == 2); + testing.expect(list.first.?.data == 2); + testing.expect(list.last.?.data == 4); + testing.expect(list.len == 2); } test "linked list concatenation" { @@ -294,18 +295,18 @@ test "linked list concatenation" { list1.concatByMoving(&list2); - assert(list1.last == five); - assert(list1.len == 5); - assert(list2.first == null); - assert(list2.last == null); - assert(list2.len == 0); + testing.expect(list1.last == five); + testing.expect(list1.len == 5); + testing.expect(list2.first == null); + testing.expect(list2.last == null); + testing.expect(list2.len == 0); // Traverse forwards. { var it = list1.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -315,7 +316,7 @@ test "linked list concatenation" { var it = list1.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } @@ -328,7 +329,7 @@ test "linked list concatenation" { var it = list2.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -338,7 +339,7 @@ test "linked list concatenation" { var it = list2.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } diff --git a/std/math/acos.zig b/std/math/acos.zig index 54844e8f6e..734f7a8651 100644 --- a/std/math/acos.zig +++ b/std/math/acos.zig @@ -4,7 +4,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn acos(x: var) @typeOf(x) { const T = @typeOf(x); @@ -143,38 +143,38 @@ fn acos64(x: f64) f64 { } test "math.acos" { - assert(acos(f32(0.0)) == acos32(0.0)); - assert(acos(f64(0.0)) == acos64(0.0)); + expect(acos(f32(0.0)) == acos32(0.0)); + expect(acos(f64(0.0)) == acos64(0.0)); } test "math.acos32" { const epsilon = 0.000001; - assert(math.approxEq(f32, acos32(0.0), 1.570796, epsilon)); - assert(math.approxEq(f32, acos32(0.2), 1.369438, epsilon)); - assert(math.approxEq(f32, acos32(0.3434), 1.220262, epsilon)); - assert(math.approxEq(f32, acos32(0.5), 1.047198, epsilon)); - assert(math.approxEq(f32, acos32(0.8923), 0.468382, epsilon)); - assert(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon)); + expect(math.approxEq(f32, acos32(0.0), 1.570796, epsilon)); + expect(math.approxEq(f32, acos32(0.2), 1.369438, epsilon)); + expect(math.approxEq(f32, acos32(0.3434), 1.220262, epsilon)); + expect(math.approxEq(f32, acos32(0.5), 1.047198, epsilon)); + expect(math.approxEq(f32, acos32(0.8923), 0.468382, epsilon)); + expect(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon)); } test "math.acos64" { const epsilon = 0.000001; - assert(math.approxEq(f64, acos64(0.0), 1.570796, epsilon)); - assert(math.approxEq(f64, acos64(0.2), 1.369438, epsilon)); - assert(math.approxEq(f64, acos64(0.3434), 1.220262, epsilon)); - assert(math.approxEq(f64, acos64(0.5), 1.047198, epsilon)); - assert(math.approxEq(f64, acos64(0.8923), 0.468382, epsilon)); - assert(math.approxEq(f64, acos64(-0.2), 1.772154, epsilon)); + expect(math.approxEq(f64, acos64(0.0), 1.570796, epsilon)); + expect(math.approxEq(f64, acos64(0.2), 1.369438, epsilon)); + expect(math.approxEq(f64, acos64(0.3434), 1.220262, epsilon)); + expect(math.approxEq(f64, acos64(0.5), 1.047198, epsilon)); + expect(math.approxEq(f64, acos64(0.8923), 0.468382, epsilon)); + expect(math.approxEq(f64, acos64(-0.2), 1.772154, epsilon)); } test "math.acos32.special" { - assert(math.isNan(acos32(-2))); - assert(math.isNan(acos32(1.5))); + expect(math.isNan(acos32(-2))); + expect(math.isNan(acos32(1.5))); } test "math.acos64.special" { - assert(math.isNan(acos64(-2))); - assert(math.isNan(acos64(1.5))); + expect(math.isNan(acos64(-2))); + expect(math.isNan(acos64(1.5))); } diff --git a/std/math/acosh.zig b/std/math/acosh.zig index 9be323e1f6..a9c4a908ef 100644 --- a/std/math/acosh.zig +++ b/std/math/acosh.zig @@ -6,7 +6,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn acosh(x: var) @typeOf(x) { const T = @typeOf(x); @@ -55,34 +55,34 @@ fn acosh64(x: f64) f64 { } test "math.acosh" { - assert(acosh(f32(1.5)) == acosh32(1.5)); - assert(acosh(f64(1.5)) == acosh64(1.5)); + expect(acosh(f32(1.5)) == acosh32(1.5)); + expect(acosh(f64(1.5)) == acosh64(1.5)); } test "math.acosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon)); - assert(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon)); - assert(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon)); - assert(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon)); + expect(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon)); + expect(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon)); + expect(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon)); } test "math.acosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon)); - assert(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon)); - assert(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon)); - assert(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon)); + expect(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon)); + expect(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon)); + expect(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon)); } test "math.acosh32.special" { - assert(math.isNan(acosh32(math.nan(f32)))); - assert(math.isSignalNan(acosh32(0.5))); + expect(math.isNan(acosh32(math.nan(f32)))); + expect(math.isSignalNan(acosh32(0.5))); } test "math.acosh64.special" { - assert(math.isNan(acosh64(math.nan(f64)))); - assert(math.isSignalNan(acosh64(0.5))); + expect(math.isNan(acosh64(math.nan(f64)))); + expect(math.isSignalNan(acosh64(0.5))); } diff --git a/std/math/asin.zig b/std/math/asin.zig index 30b3a57e32..c9dbdf704f 100644 --- a/std/math/asin.zig +++ b/std/math/asin.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn asin(x: var) @typeOf(x) { const T = @typeOf(x); @@ -136,42 +136,42 @@ fn asin64(x: f64) f64 { } test "math.asin" { - assert(asin(f32(0.0)) == asin32(0.0)); - assert(asin(f64(0.0)) == asin64(0.0)); + expect(asin(f32(0.0)) == asin32(0.0)); + expect(asin(f64(0.0)) == asin64(0.0)); } test "math.asin32" { const epsilon = 0.000001; - assert(math.approxEq(f32, asin32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, asin32(0.2), 0.201358, epsilon)); - assert(math.approxEq(f32, asin32(-0.2), -0.201358, epsilon)); - assert(math.approxEq(f32, asin32(0.3434), 0.350535, epsilon)); - assert(math.approxEq(f32, asin32(0.5), 0.523599, epsilon)); - assert(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon)); + expect(math.approxEq(f32, asin32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, asin32(0.2), 0.201358, epsilon)); + expect(math.approxEq(f32, asin32(-0.2), -0.201358, epsilon)); + expect(math.approxEq(f32, asin32(0.3434), 0.350535, epsilon)); + expect(math.approxEq(f32, asin32(0.5), 0.523599, epsilon)); + expect(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon)); } test "math.asin64" { const epsilon = 0.000001; - assert(math.approxEq(f64, asin64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, asin64(0.2), 0.201358, epsilon)); - assert(math.approxEq(f64, asin64(-0.2), -0.201358, epsilon)); - assert(math.approxEq(f64, asin64(0.3434), 0.350535, epsilon)); - assert(math.approxEq(f64, asin64(0.5), 0.523599, epsilon)); - assert(math.approxEq(f64, asin64(0.8923), 1.102415, epsilon)); + expect(math.approxEq(f64, asin64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, asin64(0.2), 0.201358, epsilon)); + expect(math.approxEq(f64, asin64(-0.2), -0.201358, epsilon)); + expect(math.approxEq(f64, asin64(0.3434), 0.350535, epsilon)); + expect(math.approxEq(f64, asin64(0.5), 0.523599, epsilon)); + expect(math.approxEq(f64, asin64(0.8923), 1.102415, epsilon)); } test "math.asin32.special" { - assert(asin32(0.0) == 0.0); - assert(asin32(-0.0) == -0.0); - assert(math.isNan(asin32(-2))); - assert(math.isNan(asin32(1.5))); + expect(asin32(0.0) == 0.0); + expect(asin32(-0.0) == -0.0); + expect(math.isNan(asin32(-2))); + expect(math.isNan(asin32(1.5))); } test "math.asin64.special" { - assert(asin64(0.0) == 0.0); - assert(asin64(-0.0) == -0.0); - assert(math.isNan(asin64(-2))); - assert(math.isNan(asin64(1.5))); + expect(asin64(0.0) == 0.0); + expect(asin64(-0.0) == -0.0); + expect(math.isNan(asin64(-2))); + expect(math.isNan(asin64(1.5))); } diff --git a/std/math/asinh.zig b/std/math/asinh.zig index 98892bcbcb..05bd8d008e 100644 --- a/std/math/asinh.zig +++ b/std/math/asinh.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn asinh(x: var) @typeOf(x) { @@ -83,46 +83,46 @@ fn asinh64(x: f64) f64 { } test "math.asinh" { - assert(asinh(f32(0.0)) == asinh32(0.0)); - assert(asinh(f64(0.0)) == asinh64(0.0)); + expect(asinh(f32(0.0)) == asinh32(0.0)); + expect(asinh(f64(0.0)) == asinh64(0.0)); } test "math.asinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, asinh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon)); - assert(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon)); - assert(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon)); - assert(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon)); - assert(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f32, asinh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon)); + expect(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon)); + expect(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon)); + expect(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon)); + expect(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon)); + expect(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon)); } test "math.asinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, asinh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon)); - assert(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon)); - assert(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon)); - assert(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon)); - assert(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f64, asinh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon)); + expect(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon)); + expect(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon)); + expect(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon)); + expect(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon)); + expect(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon)); } test "math.asinh32.special" { - assert(asinh32(0.0) == 0.0); - assert(asinh32(-0.0) == -0.0); - assert(math.isPositiveInf(asinh32(math.inf(f32)))); - assert(math.isNegativeInf(asinh32(-math.inf(f32)))); - assert(math.isNan(asinh32(math.nan(f32)))); + expect(asinh32(0.0) == 0.0); + expect(asinh32(-0.0) == -0.0); + expect(math.isPositiveInf(asinh32(math.inf(f32)))); + expect(math.isNegativeInf(asinh32(-math.inf(f32)))); + expect(math.isNan(asinh32(math.nan(f32)))); } test "math.asinh64.special" { - assert(asinh64(0.0) == 0.0); - assert(asinh64(-0.0) == -0.0); - assert(math.isPositiveInf(asinh64(math.inf(f64)))); - assert(math.isNegativeInf(asinh64(-math.inf(f64)))); - assert(math.isNan(asinh64(math.nan(f64)))); + expect(asinh64(0.0) == 0.0); + expect(asinh64(-0.0) == -0.0); + expect(math.isPositiveInf(asinh64(math.inf(f64)))); + expect(math.isNegativeInf(asinh64(-math.inf(f64)))); + expect(math.isNan(asinh64(math.nan(f64)))); } diff --git a/std/math/atan.zig b/std/math/atan.zig index 6ca94dd84a..72d17b4db2 100644 --- a/std/math/atan.zig +++ b/std/math/atan.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn atan(x: var) @typeOf(x) { const T = @typeOf(x); @@ -206,44 +206,44 @@ fn atan64(x_: f64) f64 { } test "math.atan" { - assert(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2))); - assert(atan(f64(0.2)) == atan64(0.2)); + expect(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2))); + expect(atan(f64(0.2)) == atan64(0.2)); } test "math.atan32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atan32(0.2), 0.197396, epsilon)); - assert(math.approxEq(f32, atan32(-0.2), -0.197396, epsilon)); - assert(math.approxEq(f32, atan32(0.3434), 0.330783, epsilon)); - assert(math.approxEq(f32, atan32(0.8923), 0.728545, epsilon)); - assert(math.approxEq(f32, atan32(1.5), 0.982794, epsilon)); + expect(math.approxEq(f32, atan32(0.2), 0.197396, epsilon)); + expect(math.approxEq(f32, atan32(-0.2), -0.197396, epsilon)); + expect(math.approxEq(f32, atan32(0.3434), 0.330783, epsilon)); + expect(math.approxEq(f32, atan32(0.8923), 0.728545, epsilon)); + expect(math.approxEq(f32, atan32(1.5), 0.982794, epsilon)); } test "math.atan64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atan64(0.2), 0.197396, epsilon)); - assert(math.approxEq(f64, atan64(-0.2), -0.197396, epsilon)); - assert(math.approxEq(f64, atan64(0.3434), 0.330783, epsilon)); - assert(math.approxEq(f64, atan64(0.8923), 0.728545, epsilon)); - assert(math.approxEq(f64, atan64(1.5), 0.982794, epsilon)); + expect(math.approxEq(f64, atan64(0.2), 0.197396, epsilon)); + expect(math.approxEq(f64, atan64(-0.2), -0.197396, epsilon)); + expect(math.approxEq(f64, atan64(0.3434), 0.330783, epsilon)); + expect(math.approxEq(f64, atan64(0.8923), 0.728545, epsilon)); + expect(math.approxEq(f64, atan64(1.5), 0.982794, epsilon)); } test "math.atan32.special" { const epsilon = 0.000001; - assert(atan32(0.0) == 0.0); - assert(atan32(-0.0) == -0.0); - assert(math.approxEq(f32, atan32(math.inf(f32)), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan32(-math.inf(f32)), -math.pi / 2.0, epsilon)); + expect(atan32(0.0) == 0.0); + expect(atan32(-0.0) == -0.0); + expect(math.approxEq(f32, atan32(math.inf(f32)), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan32(-math.inf(f32)), -math.pi / 2.0, epsilon)); } test "math.atan64.special" { const epsilon = 0.000001; - assert(atan64(0.0) == 0.0); - assert(atan64(-0.0) == -0.0); - assert(math.approxEq(f64, atan64(math.inf(f64)), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan64(-math.inf(f64)), -math.pi / 2.0, epsilon)); + expect(atan64(0.0) == 0.0); + expect(atan64(-0.0) == -0.0); + expect(math.approxEq(f64, atan64(math.inf(f64)), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan64(-math.inf(f64)), -math.pi / 2.0, epsilon)); } diff --git a/std/math/atan2.zig b/std/math/atan2.zig index a7757132d7..6e1f67cfbb 100644 --- a/std/math/atan2.zig +++ b/std/math/atan2.zig @@ -20,7 +20,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn atan2(comptime T: type, y: T, x: T) T { return switch (T) { @@ -206,78 +206,78 @@ fn atan2_64(y: f64, x: f64) f64 { } test "math.atan2" { - assert(atan2(f32, 0.2, 0.21) == atan2_32(0.2, 0.21)); - assert(atan2(f64, 0.2, 0.21) == atan2_64(0.2, 0.21)); + expect(atan2(f32, 0.2, 0.21) == atan2_32(0.2, 0.21)); + expect(atan2(f64, 0.2, 0.21) == atan2_64(0.2, 0.21)); } test "math.atan2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon)); + expect(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon)); + expect(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon)); + expect(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon)); + expect(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon)); + expect(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon)); + expect(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon)); + expect(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon)); } test "math.atan2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon)); + expect(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon)); + expect(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon)); + expect(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon)); + expect(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon)); + expect(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon)); + expect(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon)); + expect(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon)); } test "math.atan2_32.special" { const epsilon = 0.000001; - assert(math.isNan(atan2_32(1.0, math.nan(f32)))); - assert(math.isNan(atan2_32(math.nan(f32), 1.0))); - assert(atan2_32(0.0, 5.0) == 0.0); - assert(atan2_32(-0.0, 5.0) == -0.0); - assert(math.approxEq(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); - //assert(math.approxEq(f32, atan2_32(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? - assert(math.approxEq(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(1.0, -0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, 0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, -0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), math.inf(f32)), math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), math.inf(f32)), -math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), -math.inf(f32)), 3.0 * math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), -math.inf(f32)), -3.0 * math.pi / 4.0, epsilon)); - assert(atan2_32(1.0, math.inf(f32)) == 0.0); - assert(math.approxEq(f32, atan2_32(1.0, -math.inf(f32)), math.pi, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, -math.inf(f32)), -math.pi, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), 1.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), 1.0), -math.pi / 2.0, epsilon)); + expect(math.isNan(atan2_32(1.0, math.nan(f32)))); + expect(math.isNan(atan2_32(math.nan(f32), 1.0))); + expect(atan2_32(0.0, 5.0) == 0.0); + expect(atan2_32(-0.0, 5.0) == -0.0); + expect(math.approxEq(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); + //expect(math.approxEq(f32, atan2_32(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? + expect(math.approxEq(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(1.0, -0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, 0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, -0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), math.inf(f32)), math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), math.inf(f32)), -math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), -math.inf(f32)), 3.0 * math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), -math.inf(f32)), -3.0 * math.pi / 4.0, epsilon)); + expect(atan2_32(1.0, math.inf(f32)) == 0.0); + expect(math.approxEq(f32, atan2_32(1.0, -math.inf(f32)), math.pi, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, -math.inf(f32)), -math.pi, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), 1.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), 1.0), -math.pi / 2.0, epsilon)); } test "math.atan2_64.special" { const epsilon = 0.000001; - assert(math.isNan(atan2_64(1.0, math.nan(f64)))); - assert(math.isNan(atan2_64(math.nan(f64), 1.0))); - assert(atan2_64(0.0, 5.0) == 0.0); - assert(atan2_64(-0.0, 5.0) == -0.0); - assert(math.approxEq(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); - //assert(math.approxEq(f64, atan2_64(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? - assert(math.approxEq(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(1.0, -0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, 0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, -0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), math.inf(f64)), math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), math.inf(f64)), -math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), -math.inf(f64)), 3.0 * math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), -math.inf(f64)), -3.0 * math.pi / 4.0, epsilon)); - assert(atan2_64(1.0, math.inf(f64)) == 0.0); - assert(math.approxEq(f64, atan2_64(1.0, -math.inf(f64)), math.pi, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, -math.inf(f64)), -math.pi, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), 1.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), 1.0), -math.pi / 2.0, epsilon)); + expect(math.isNan(atan2_64(1.0, math.nan(f64)))); + expect(math.isNan(atan2_64(math.nan(f64), 1.0))); + expect(atan2_64(0.0, 5.0) == 0.0); + expect(atan2_64(-0.0, 5.0) == -0.0); + expect(math.approxEq(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); + //expect(math.approxEq(f64, atan2_64(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? + expect(math.approxEq(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(1.0, -0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, 0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, -0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), math.inf(f64)), math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), math.inf(f64)), -math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), -math.inf(f64)), 3.0 * math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), -math.inf(f64)), -3.0 * math.pi / 4.0, epsilon)); + expect(atan2_64(1.0, math.inf(f64)) == 0.0); + expect(math.approxEq(f64, atan2_64(1.0, -math.inf(f64)), math.pi, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, -math.inf(f64)), -math.pi, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), 1.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), 1.0), -math.pi / 2.0, epsilon)); } diff --git a/std/math/atanh.zig b/std/math/atanh.zig index c97855c234..f2feab0207 100644 --- a/std/math/atanh.zig +++ b/std/math/atanh.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn atanh(x: var) @typeOf(x) { @@ -78,38 +78,38 @@ fn atanh_64(x: f64) f64 { } test "math.atanh" { - assert(atanh(f32(0.0)) == atanh_32(0.0)); - assert(atanh(f64(0.0)) == atanh_64(0.0)); + expect(atanh(f32(0.0)) == atanh_32(0.0)); + expect(atanh(f64(0.0)) == atanh_64(0.0)); } test "math.atanh_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon)); - assert(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon)); + expect(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon)); + expect(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon)); } test "math.atanh_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon)); - assert(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon)); + expect(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon)); + expect(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon)); } test "math.atanh32.special" { - assert(math.isPositiveInf(atanh_32(1))); - assert(math.isNegativeInf(atanh_32(-1))); - assert(math.isSignalNan(atanh_32(1.5))); - assert(math.isSignalNan(atanh_32(-1.5))); - assert(math.isNan(atanh_32(math.nan(f32)))); + expect(math.isPositiveInf(atanh_32(1))); + expect(math.isNegativeInf(atanh_32(-1))); + expect(math.isSignalNan(atanh_32(1.5))); + expect(math.isSignalNan(atanh_32(-1.5))); + expect(math.isNan(atanh_32(math.nan(f32)))); } test "math.atanh64.special" { - assert(math.isPositiveInf(atanh_64(1))); - assert(math.isNegativeInf(atanh_64(-1))); - assert(math.isSignalNan(atanh_64(1.5))); - assert(math.isSignalNan(atanh_64(-1.5))); - assert(math.isNan(atanh_64(math.nan(f64)))); + expect(math.isPositiveInf(atanh_64(1))); + expect(math.isNegativeInf(atanh_64(-1))); + expect(math.isSignalNan(atanh_64(1.5))); + expect(math.isSignalNan(atanh_64(-1.5))); + expect(math.isNan(atanh_64(math.nan(f64)))); } diff --git a/std/math/big/int.zig b/std/math/big/int.zig index cda2e1419f..f21e5df8aa 100644 --- a/std/math/big/int.zig +++ b/std/math/big/int.zig @@ -1,6 +1,7 @@ const std = @import("../../index.zig"); const builtin = @import("builtin"); const debug = std.debug; +const testing = std.testing; const math = std.math; const mem = std.mem; const Allocator = mem.Allocator; @@ -1086,44 +1087,40 @@ test "big.int comptime_int set" { const result = Limb(s & maxInt(Limb)); s >>= Limb.bit_count / 2; s >>= Limb.bit_count / 2; - debug.assert(a.limbs[i] == result); + testing.expect(a.limbs[i] == result); } } test "big.int comptime_int set negative" { var a = try Int.initSet(al, -10); - debug.assert(a.limbs[0] == 10); - debug.assert(a.positive == false); + testing.expect(a.limbs[0] == 10); + testing.expect(a.positive == false); } test "big.int int set unaligned small" { var a = try Int.initSet(al, u7(45)); - debug.assert(a.limbs[0] == 45); - debug.assert(a.positive == true); + testing.expect(a.limbs[0] == 45); + testing.expect(a.positive == true); } test "big.int comptime_int to" { const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab); - debug.assert((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab); + testing.expect((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab); } test "big.int sub-limb to" { const a = try Int.initSet(al, 10); - debug.assert((try a.to(u8)) == 10); + testing.expect((try a.to(u8)) == 10); } test "big.int to target too small error" { const a = try Int.initSet(al, 0xffffffff); - if (a.to(u8)) |_| { - unreachable; - } else |err| { - debug.assert(err == error.TargetTooSmall); - } + testing.expectError(error.TargetTooSmall, a.to(u8)); } test "big.int norm1" { @@ -1135,22 +1132,22 @@ test "big.int norm1" { a.limbs[2] = 3; a.limbs[3] = 0; a.norm1(4); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; a.norm1(3); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 0; a.limbs[1] = 0; a.norm1(2); - debug.assert(a.len == 1); + testing.expect(a.len == 1); a.limbs[0] = 0; a.norm1(1); - debug.assert(a.len == 1); + testing.expect(a.len == 1); } test "big.int normN" { @@ -1162,144 +1159,144 @@ test "big.int normN" { a.limbs[2] = 0; a.limbs[3] = 0; a.normN(4); - debug.assert(a.len == 2); + testing.expect(a.len == 2); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; a.normN(3); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 0; a.limbs[1] = 0; a.limbs[2] = 0; a.limbs[3] = 0; a.normN(4); - debug.assert(a.len == 1); + testing.expect(a.len == 1); a.limbs[0] = 0; a.normN(1); - debug.assert(a.len == 1); + testing.expect(a.len == 1); } test "big.int parity" { var a = try Int.init(al); try a.set(0); - debug.assert(a.isEven()); - debug.assert(!a.isOdd()); + testing.expect(a.isEven()); + testing.expect(!a.isOdd()); try a.set(7); - debug.assert(!a.isEven()); - debug.assert(a.isOdd()); + testing.expect(!a.isEven()); + testing.expect(a.isOdd()); } test "big.int bitcount + sizeInBase" { var a = try Int.init(al); try a.set(0b100); - debug.assert(a.bitCountAbs() == 3); - debug.assert(a.sizeInBase(2) >= 3); - debug.assert(a.sizeInBase(10) >= 1); + testing.expect(a.bitCountAbs() == 3); + testing.expect(a.sizeInBase(2) >= 3); + testing.expect(a.sizeInBase(10) >= 1); a.negate(); - debug.assert(a.bitCountAbs() == 3); - debug.assert(a.sizeInBase(2) >= 4); - debug.assert(a.sizeInBase(10) >= 2); + testing.expect(a.bitCountAbs() == 3); + testing.expect(a.sizeInBase(2) >= 4); + testing.expect(a.sizeInBase(10) >= 2); try a.set(0xffffffff); - debug.assert(a.bitCountAbs() == 32); - debug.assert(a.sizeInBase(2) >= 32); - debug.assert(a.sizeInBase(10) >= 10); + testing.expect(a.bitCountAbs() == 32); + testing.expect(a.sizeInBase(2) >= 32); + testing.expect(a.sizeInBase(10) >= 10); try a.shiftLeft(a, 5000); - debug.assert(a.bitCountAbs() == 5032); - debug.assert(a.sizeInBase(2) >= 5032); + testing.expect(a.bitCountAbs() == 5032); + testing.expect(a.sizeInBase(2) >= 5032); a.positive = false; - debug.assert(a.bitCountAbs() == 5032); - debug.assert(a.sizeInBase(2) >= 5033); + testing.expect(a.bitCountAbs() == 5032); + testing.expect(a.sizeInBase(2) >= 5033); } test "big.int bitcount/to" { var a = try Int.init(al); try a.set(0); - debug.assert(a.bitCountTwosComp() == 0); + testing.expect(a.bitCountTwosComp() == 0); // TODO: stack smashing - // debug.assert((try a.to(u0)) == 0); + // testing.expect((try a.to(u0)) == 0); // TODO: sigsegv - // debug.assert((try a.to(i0)) == 0); + // testing.expect((try a.to(i0)) == 0); try a.set(-1); - debug.assert(a.bitCountTwosComp() == 1); - debug.assert((try a.to(i1)) == -1); + testing.expect(a.bitCountTwosComp() == 1); + testing.expect((try a.to(i1)) == -1); try a.set(-8); - debug.assert(a.bitCountTwosComp() == 4); - debug.assert((try a.to(i4)) == -8); + testing.expect(a.bitCountTwosComp() == 4); + testing.expect((try a.to(i4)) == -8); try a.set(127); - debug.assert(a.bitCountTwosComp() == 7); - debug.assert((try a.to(u7)) == 127); + testing.expect(a.bitCountTwosComp() == 7); + testing.expect((try a.to(u7)) == 127); try a.set(-128); - debug.assert(a.bitCountTwosComp() == 8); - debug.assert((try a.to(i8)) == -128); + testing.expect(a.bitCountTwosComp() == 8); + testing.expect((try a.to(i8)) == -128); try a.set(-129); - debug.assert(a.bitCountTwosComp() == 9); - debug.assert((try a.to(i9)) == -129); + testing.expect(a.bitCountTwosComp() == 9); + testing.expect((try a.to(i9)) == -129); } test "big.int fits" { var a = try Int.init(al); try a.set(0); - debug.assert(a.fits(u0)); - debug.assert(a.fits(i0)); + testing.expect(a.fits(u0)); + testing.expect(a.fits(i0)); try a.set(255); - debug.assert(!a.fits(u0)); - debug.assert(!a.fits(u1)); - debug.assert(!a.fits(i8)); - debug.assert(a.fits(u8)); - debug.assert(a.fits(u9)); - debug.assert(a.fits(i9)); + testing.expect(!a.fits(u0)); + testing.expect(!a.fits(u1)); + testing.expect(!a.fits(i8)); + testing.expect(a.fits(u8)); + testing.expect(a.fits(u9)); + testing.expect(a.fits(i9)); try a.set(-128); - debug.assert(!a.fits(i7)); - debug.assert(a.fits(i8)); - debug.assert(a.fits(i9)); - debug.assert(!a.fits(u9)); + testing.expect(!a.fits(i7)); + testing.expect(a.fits(i8)); + testing.expect(a.fits(i9)); + testing.expect(!a.fits(u9)); try a.set(0x1ffffffffeeeeeeee); - debug.assert(!a.fits(u32)); - debug.assert(!a.fits(u64)); - debug.assert(a.fits(u65)); + testing.expect(!a.fits(u32)); + testing.expect(!a.fits(u64)); + testing.expect(a.fits(u65)); } test "big.int string set" { var a = try Int.init(al); try a.setString(10, "120317241209124781241290847124"); - debug.assert((try a.to(u128)) == 120317241209124781241290847124); + testing.expect((try a.to(u128)) == 120317241209124781241290847124); } test "big.int string negative" { var a = try Int.init(al); try a.setString(10, "-1023"); - debug.assert((try a.to(i32)) == -1023); + testing.expect((try a.to(i32)) == -1023); } test "big.int string set bad char error" { var a = try Int.init(al); - a.setString(10, "x") catch |err| debug.assert(err == error.InvalidCharForDigit); + testing.expectError(error.InvalidCharForDigit, a.setString(10, "x")); } test "big.int string set bad base error" { var a = try Int.init(al); - a.setString(45, "10") catch |err| debug.assert(err == error.InvalidBase); + testing.expectError(error.InvalidBase, a.setString(45, "10")); } test "big.int string to" { @@ -1308,17 +1305,13 @@ test "big.int string to" { const as = try a.toString(al, 10); const es = "120317241209124781241290847124"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int string to base base error" { const a = try Int.initSet(al, 0xffffffff); - if (a.toString(al, 45)) |_| { - unreachable; - } else |err| { - debug.assert(err == error.InvalidBase); - } + testing.expectError(error.InvalidBase, a.toString(al, 45)); } test "big.int string to base 2" { @@ -1327,7 +1320,7 @@ test "big.int string to base 2" { const as = try a.toString(al, 2); const es = "-1011"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int string to base 16" { @@ -1336,7 +1329,7 @@ test "big.int string to base 16" { const as = try a.toString(al, 16); const es = "efffffff00000001eeeeeeefaaaaaaab"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int neg string to" { @@ -1345,7 +1338,7 @@ test "big.int neg string to" { const as = try a.toString(al, 10); const es = "-123907434"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int zero string to" { @@ -1354,98 +1347,98 @@ test "big.int zero string to" { const as = try a.toString(al, 10); const es = "0"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int clone" { var a = try Int.initSet(al, 1234); const b = try a.clone(); - debug.assert((try a.to(u32)) == 1234); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 1234); + testing.expect((try b.to(u32)) == 1234); try a.set(77); - debug.assert((try a.to(u32)) == 77); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 77); + testing.expect((try b.to(u32)) == 1234); } test "big.int swap" { var a = try Int.initSet(al, 1234); var b = try Int.initSet(al, 5678); - debug.assert((try a.to(u32)) == 1234); - debug.assert((try b.to(u32)) == 5678); + testing.expect((try a.to(u32)) == 1234); + testing.expect((try b.to(u32)) == 5678); a.swap(&b); - debug.assert((try a.to(u32)) == 5678); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 5678); + testing.expect((try b.to(u32)) == 1234); } test "big.int to negative" { var a = try Int.initSet(al, -10); - debug.assert((try a.to(i32)) == -10); + testing.expect((try a.to(i32)) == -10); } test "big.int compare" { var a = try Int.initSet(al, -11); var b = try Int.initSet(al, 10); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(a.cmp(b) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(a.cmp(b) == -1); } test "big.int compare similar" { var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee); var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef); - debug.assert(a.cmpAbs(b) == -1); - debug.assert(b.cmpAbs(a) == 1); + testing.expect(a.cmpAbs(b) == -1); + testing.expect(b.cmpAbs(a) == 1); } test "big.int compare different limb size" { var a = try Int.initSet(al, maxInt(Limb) + 1); var b = try Int.initSet(al, 1); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(b.cmpAbs(a) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(b.cmpAbs(a) == -1); } test "big.int compare multi-limb" { var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef); var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(a.cmp(b) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(a.cmp(b) == -1); } test "big.int equality" { var a = try Int.initSet(al, 0xffffffff1); var b = try Int.initSet(al, -0xffffffff1); - debug.assert(a.eqAbs(b)); - debug.assert(!a.eq(b)); + testing.expect(a.eqAbs(b)); + testing.expect(!a.eq(b)); } test "big.int abs" { var a = try Int.initSet(al, -5); a.abs(); - debug.assert((try a.to(u32)) == 5); + testing.expect((try a.to(u32)) == 5); a.abs(); - debug.assert((try a.to(u32)) == 5); + testing.expect((try a.to(u32)) == 5); } test "big.int negate" { var a = try Int.initSet(al, 5); a.negate(); - debug.assert((try a.to(i32)) == -5); + testing.expect((try a.to(i32)) == -5); a.negate(); - debug.assert((try a.to(i32)) == 5); + testing.expect((try a.to(i32)) == 5); } test "big.int add single-single" { @@ -1455,7 +1448,7 @@ test "big.int add single-single" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u32)) == 55); + testing.expect((try c.to(u32)) == 55); } test "big.int add multi-single" { @@ -1465,10 +1458,10 @@ test "big.int add multi-single" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(DoubleLimb)) == maxInt(Limb) + 2); + testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2); try c.add(b, a); - debug.assert((try c.to(DoubleLimb)) == maxInt(Limb) + 2); + testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2); } test "big.int add multi-multi" { @@ -1480,7 +1473,7 @@ test "big.int add multi-multi" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u128)) == op1 + op2); + testing.expect((try c.to(u128)) == op1 + op2); } test "big.int add zero-zero" { @@ -1490,7 +1483,7 @@ test "big.int add zero-zero" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int add alias multi-limb nonzero-zero" { @@ -1500,7 +1493,7 @@ test "big.int add alias multi-limb nonzero-zero" { try a.add(a, b); - debug.assert((try a.to(u128)) == op1); + testing.expect((try a.to(u128)) == op1); } test "big.int add sign" { @@ -1512,16 +1505,16 @@ test "big.int add sign" { const neg_two = try Int.initSet(al, -2); try a.add(one, two); - debug.assert((try a.to(i32)) == 3); + testing.expect((try a.to(i32)) == 3); try a.add(neg_one, two); - debug.assert((try a.to(i32)) == 1); + testing.expect((try a.to(i32)) == 1); try a.add(one, neg_two); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); try a.add(neg_one, neg_two); - debug.assert((try a.to(i32)) == -3); + testing.expect((try a.to(i32)) == -3); } test "big.int sub single-single" { @@ -1531,7 +1524,7 @@ test "big.int sub single-single" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u32)) == 45); + testing.expect((try c.to(u32)) == 45); } test "big.int sub multi-single" { @@ -1541,7 +1534,7 @@ test "big.int sub multi-single" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(Limb)) == maxInt(Limb)); + testing.expect((try c.to(Limb)) == maxInt(Limb)); } test "big.int sub multi-multi" { @@ -1554,7 +1547,7 @@ test "big.int sub multi-multi" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u128)) == op1 - op2); + testing.expect((try c.to(u128)) == op1 - op2); } test "big.int sub equal" { @@ -1564,7 +1557,7 @@ test "big.int sub equal" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int sub sign" { @@ -1576,19 +1569,19 @@ test "big.int sub sign" { const neg_two = try Int.initSet(al, -2); try a.sub(one, two); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); try a.sub(neg_one, two); - debug.assert((try a.to(i32)) == -3); + testing.expect((try a.to(i32)) == -3); try a.sub(one, neg_two); - debug.assert((try a.to(i32)) == 3); + testing.expect((try a.to(i32)) == 3); try a.sub(neg_one, neg_two); - debug.assert((try a.to(i32)) == 1); + testing.expect((try a.to(i32)) == 1); try a.sub(neg_two, neg_one); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); } test "big.int mul single-single" { @@ -1598,7 +1591,7 @@ test "big.int mul single-single" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u64)) == 250); + testing.expect((try c.to(u64)) == 250); } test "big.int mul multi-single" { @@ -1608,7 +1601,7 @@ test "big.int mul multi-single" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try c.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul multi-multi" { @@ -1620,7 +1613,7 @@ test "big.int mul multi-multi" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u256)) == op1 * op2); + testing.expect((try c.to(u256)) == op1 * op2); } test "big.int mul alias r with a" { @@ -1629,7 +1622,7 @@ test "big.int mul alias r with a" { try a.mul(a, b); - debug.assert((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul alias r with b" { @@ -1638,7 +1631,7 @@ test "big.int mul alias r with b" { try a.mul(b, a); - debug.assert((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul alias r with a and b" { @@ -1646,7 +1639,7 @@ test "big.int mul alias r with a and b" { try a.mul(a, a); - debug.assert((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb)); } test "big.int mul a*0" { @@ -1656,7 +1649,7 @@ test "big.int mul a*0" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int mul 0*0" { @@ -1666,7 +1659,7 @@ test "big.int mul 0*0" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int div single-single no rem" { @@ -1677,8 +1670,8 @@ test "big.int div single-single no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u32)) == 10); - debug.assert((try r.to(u32)) == 0); + testing.expect((try q.to(u32)) == 10); + testing.expect((try r.to(u32)) == 0); } test "big.int div single-single with rem" { @@ -1689,8 +1682,8 @@ test "big.int div single-single with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u32)) == 9); - debug.assert((try r.to(u32)) == 4); + testing.expect((try q.to(u32)) == 9); + testing.expect((try r.to(u32)) == 4); } test "big.int div multi-single no rem" { @@ -1704,8 +1697,8 @@ test "big.int div multi-single no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == op1 / op2); - debug.assert((try r.to(u64)) == 0); + testing.expect((try q.to(u64)) == op1 / op2); + testing.expect((try r.to(u64)) == 0); } test "big.int div multi-single with rem" { @@ -1719,8 +1712,8 @@ test "big.int div multi-single with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == op1 / op2); - debug.assert((try r.to(u64)) == 3); + testing.expect((try q.to(u64)) == op1 / op2); + testing.expect((try r.to(u64)) == 3); } test "big.int div multi>2-single" { @@ -1734,8 +1727,8 @@ test "big.int div multi>2-single" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == op1 / op2); - debug.assert((try r.to(u32)) == 0x3e4e); + testing.expect((try q.to(u128)) == op1 / op2); + testing.expect((try r.to(u32)) == 0x3e4e); } test "big.int div single-single q < r" { @@ -1746,8 +1739,8 @@ test "big.int div single-single q < r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == 0); - debug.assert((try r.to(u64)) == 0x0078f432); + testing.expect((try q.to(u64)) == 0); + testing.expect((try r.to(u64)) == 0x0078f432); } test "big.int div single-single q == r" { @@ -1758,8 +1751,8 @@ test "big.int div single-single q == r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == 1); - debug.assert((try r.to(u64)) == 0); + testing.expect((try q.to(u64)) == 1); + testing.expect((try r.to(u64)) == 0); } test "big.int div q=0 alias" { @@ -1768,8 +1761,8 @@ test "big.int div q=0 alias" { try Int.divTrunc(&a, &b, a, b); - debug.assert((try a.to(u64)) == 0); - debug.assert((try b.to(u64)) == 3); + testing.expect((try a.to(u64)) == 0); + testing.expect((try b.to(u64)) == 3); } test "big.int div multi-multi q < r" { @@ -1782,8 +1775,8 @@ test "big.int div multi-multi q < r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0); - debug.assert((try r.to(u128)) == op1); + testing.expect((try q.to(u128)) == 0); + testing.expect((try r.to(u128)) == op1); } test "big.int div trunc single-single +/+" { @@ -1802,8 +1795,8 @@ test "big.int div trunc single-single +/+" { const eq = @divTrunc(u, v); const er = @mod(u, v); - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single -/+" { @@ -1822,8 +1815,8 @@ test "big.int div trunc single-single -/+" { const eq = -1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single +/-" { @@ -1842,8 +1835,8 @@ test "big.int div trunc single-single +/-" { const eq = -1; const er = 2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single -/-" { @@ -1862,8 +1855,8 @@ test "big.int div trunc single-single -/-" { const eq = 1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single +/+" { @@ -1882,8 +1875,8 @@ test "big.int div floor single-single +/+" { const eq = 1; const er = 2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single -/+" { @@ -1902,8 +1895,8 @@ test "big.int div floor single-single -/+" { const eq = -2; const er = 1; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single +/-" { @@ -1922,8 +1915,8 @@ test "big.int div floor single-single +/-" { const eq = -2; const er = -1; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single -/-" { @@ -1942,8 +1935,8 @@ test "big.int div floor single-single -/-" { const eq = 1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div multi-multi with rem" { @@ -1954,8 +1947,8 @@ test "big.int div multi-multi with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); - debug.assert((try r.to(u128)) == 0x28de0acacd806823638); + testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); + testing.expect((try r.to(u128)) == 0x28de0acacd806823638); } test "big.int div multi-multi no rem" { @@ -1966,8 +1959,8 @@ test "big.int div multi-multi no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); - debug.assert((try r.to(u128)) == 0); + testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); + testing.expect((try r.to(u128)) == 0); } test "big.int div multi-multi (2 branch)" { @@ -1978,8 +1971,8 @@ test "big.int div multi-multi (2 branch)" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0x10000000000000000); - debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111); + testing.expect((try q.to(u128)) == 0x10000000000000000); + testing.expect((try r.to(u128)) == 0x44444443444444431111111111111111); } test "big.int div multi-multi (3.1/3.3 branch)" { @@ -1990,53 +1983,53 @@ test "big.int div multi-multi (3.1/3.3 branch)" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xfffffffffffffffffff); - debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); + testing.expect((try q.to(u128)) == 0xfffffffffffffffffff); + testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); } test "big.int shift-right single" { var a = try Int.initSet(al, 0xffff0000); try a.shiftRight(a, 16); - debug.assert((try a.to(u32)) == 0xffff); + testing.expect((try a.to(u32)) == 0xffff); } test "big.int shift-right multi" { var a = try Int.initSet(al, 0xffff0000eeee1111dddd2222cccc3333); try a.shiftRight(a, 67); - debug.assert((try a.to(u64)) == 0x1fffe0001dddc222); + testing.expect((try a.to(u64)) == 0x1fffe0001dddc222); } test "big.int shift-left single" { var a = try Int.initSet(al, 0xffff); try a.shiftLeft(a, 16); - debug.assert((try a.to(u64)) == 0xffff0000); + testing.expect((try a.to(u64)) == 0xffff0000); } test "big.int shift-left multi" { var a = try Int.initSet(al, 0x1fffe0001dddc222); try a.shiftLeft(a, 67); - debug.assert((try a.to(u128)) == 0xffff0000eeee11100000000000000000); + testing.expect((try a.to(u128)) == 0xffff0000eeee11100000000000000000); } test "big.int shift-right negative" { var a = try Int.init(al); try a.shiftRight(try Int.initSet(al, -20), 2); - debug.assert((try a.to(i32)) == -20 >> 2); + testing.expect((try a.to(i32)) == -20 >> 2); try a.shiftRight(try Int.initSet(al, -5), 10); - debug.assert((try a.to(i32)) == -5 >> 10); + testing.expect((try a.to(i32)) == -5 >> 10); } test "big.int shift-left negative" { var a = try Int.init(al); try a.shiftRight(try Int.initSet(al, -10), 1232); - debug.assert((try a.to(i32)) == -10 >> 1232); + testing.expect((try a.to(i32)) == -10 >> 1232); } test "big.int bitwise and simple" { @@ -2045,7 +2038,7 @@ test "big.int bitwise and simple" { try a.bitAnd(a, b); - debug.assert((try a.to(u64)) == 0xeeeeeeee00000000); + testing.expect((try a.to(u64)) == 0xeeeeeeee00000000); } test "big.int bitwise and multi-limb" { @@ -2054,7 +2047,7 @@ test "big.int bitwise and multi-limb" { try a.bitAnd(a, b); - debug.assert((try a.to(u128)) == 0); + testing.expect((try a.to(u128)) == 0); } test "big.int bitwise xor simple" { @@ -2063,7 +2056,7 @@ test "big.int bitwise xor simple" { try a.bitXor(a, b); - debug.assert((try a.to(u64)) == 0x1111111133333333); + testing.expect((try a.to(u64)) == 0x1111111133333333); } test "big.int bitwise xor multi-limb" { @@ -2072,7 +2065,7 @@ test "big.int bitwise xor multi-limb" { try a.bitXor(a, b); - debug.assert((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb)); } test "big.int bitwise or simple" { @@ -2081,7 +2074,7 @@ test "big.int bitwise or simple" { try a.bitOr(a, b); - debug.assert((try a.to(u64)) == 0xffffffff33333333); + testing.expect((try a.to(u64)) == 0xffffffff33333333); } test "big.int bitwise or multi-limb" { @@ -2091,15 +2084,15 @@ test "big.int bitwise or multi-limb" { try a.bitOr(a, b); // TODO: big.int.cpp or is wrong on multi-limb. - debug.assert((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); } test "big.int var args" { var a = try Int.initSet(al, 5); try a.add(a, try Int.initSet(al, 6)); - debug.assert((try a.to(u64)) == 11); + testing.expect((try a.to(u64)) == 11); - debug.assert(a.cmp(try Int.initSet(al, 11)) == 0); - debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0); + testing.expect(a.cmp(try Int.initSet(al, 11)) == 0); + testing.expect(a.cmp(try Int.initSet(al, 14)) <= 0); } diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig index c067c5155a..957e026af4 100644 --- a/std/math/cbrt.zig +++ b/std/math/cbrt.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn cbrt(x: var) @typeOf(x) { const T = @typeOf(x); @@ -114,44 +114,44 @@ fn cbrt64(x: f64) f64 { } test "math.cbrt" { - assert(cbrt(f32(0.0)) == cbrt32(0.0)); - assert(cbrt(f64(0.0)) == cbrt64(0.0)); + expect(cbrt(f32(0.0)) == cbrt32(0.0)); + expect(cbrt(f64(0.0)) == cbrt64(0.0)); } test "math.cbrt32" { const epsilon = 0.000001; - assert(cbrt32(0.0) == 0.0); - assert(math.approxEq(f32, cbrt32(0.2), 0.584804, epsilon)); - assert(math.approxEq(f32, cbrt32(0.8923), 0.962728, epsilon)); - assert(math.approxEq(f32, cbrt32(1.5), 1.144714, epsilon)); - assert(math.approxEq(f32, cbrt32(37.45), 3.345676, epsilon)); - assert(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon)); + expect(cbrt32(0.0) == 0.0); + expect(math.approxEq(f32, cbrt32(0.2), 0.584804, epsilon)); + expect(math.approxEq(f32, cbrt32(0.8923), 0.962728, epsilon)); + expect(math.approxEq(f32, cbrt32(1.5), 1.144714, epsilon)); + expect(math.approxEq(f32, cbrt32(37.45), 3.345676, epsilon)); + expect(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon)); } test "math.cbrt64" { const epsilon = 0.000001; - assert(cbrt64(0.0) == 0.0); - assert(math.approxEq(f64, cbrt64(0.2), 0.584804, epsilon)); - assert(math.approxEq(f64, cbrt64(0.8923), 0.962728, epsilon)); - assert(math.approxEq(f64, cbrt64(1.5), 1.144714, epsilon)); - assert(math.approxEq(f64, cbrt64(37.45), 3.345676, epsilon)); - assert(math.approxEq(f64, cbrt64(123123.234375), 49.748501, epsilon)); + expect(cbrt64(0.0) == 0.0); + expect(math.approxEq(f64, cbrt64(0.2), 0.584804, epsilon)); + expect(math.approxEq(f64, cbrt64(0.8923), 0.962728, epsilon)); + expect(math.approxEq(f64, cbrt64(1.5), 1.144714, epsilon)); + expect(math.approxEq(f64, cbrt64(37.45), 3.345676, epsilon)); + expect(math.approxEq(f64, cbrt64(123123.234375), 49.748501, epsilon)); } test "math.cbrt.special" { - assert(cbrt32(0.0) == 0.0); - assert(cbrt32(-0.0) == -0.0); - assert(math.isPositiveInf(cbrt32(math.inf(f32)))); - assert(math.isNegativeInf(cbrt32(-math.inf(f32)))); - assert(math.isNan(cbrt32(math.nan(f32)))); + expect(cbrt32(0.0) == 0.0); + expect(cbrt32(-0.0) == -0.0); + expect(math.isPositiveInf(cbrt32(math.inf(f32)))); + expect(math.isNegativeInf(cbrt32(-math.inf(f32)))); + expect(math.isNan(cbrt32(math.nan(f32)))); } test "math.cbrt64.special" { - assert(cbrt64(0.0) == 0.0); - assert(cbrt64(-0.0) == -0.0); - assert(math.isPositiveInf(cbrt64(math.inf(f64)))); - assert(math.isNegativeInf(cbrt64(-math.inf(f64)))); - assert(math.isNan(cbrt64(math.nan(f64)))); + expect(cbrt64(0.0) == 0.0); + expect(cbrt64(-0.0) == -0.0); + expect(math.isPositiveInf(cbrt64(math.inf(f64)))); + expect(math.isNegativeInf(cbrt64(-math.inf(f64)))); + expect(math.isNan(cbrt64(math.nan(f64)))); } diff --git a/std/math/ceil.zig b/std/math/ceil.zig index 8a5221d862..5c6b98b2ca 100644 --- a/std/math/ceil.zig +++ b/std/math/ceil.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn ceil(x: var) @typeOf(x) { const T = @typeOf(x); @@ -81,34 +81,34 @@ fn ceil64(x: f64) f64 { } test "math.ceil" { - assert(ceil(f32(0.0)) == ceil32(0.0)); - assert(ceil(f64(0.0)) == ceil64(0.0)); + expect(ceil(f32(0.0)) == ceil32(0.0)); + expect(ceil(f64(0.0)) == ceil64(0.0)); } test "math.ceil32" { - assert(ceil32(1.3) == 2.0); - assert(ceil32(-1.3) == -1.0); - assert(ceil32(0.2) == 1.0); + expect(ceil32(1.3) == 2.0); + expect(ceil32(-1.3) == -1.0); + expect(ceil32(0.2) == 1.0); } test "math.ceil64" { - assert(ceil64(1.3) == 2.0); - assert(ceil64(-1.3) == -1.0); - assert(ceil64(0.2) == 1.0); + expect(ceil64(1.3) == 2.0); + expect(ceil64(-1.3) == -1.0); + expect(ceil64(0.2) == 1.0); } test "math.ceil32.special" { - assert(ceil32(0.0) == 0.0); - assert(ceil32(-0.0) == -0.0); - assert(math.isPositiveInf(ceil32(math.inf(f32)))); - assert(math.isNegativeInf(ceil32(-math.inf(f32)))); - assert(math.isNan(ceil32(math.nan(f32)))); + expect(ceil32(0.0) == 0.0); + expect(ceil32(-0.0) == -0.0); + expect(math.isPositiveInf(ceil32(math.inf(f32)))); + expect(math.isNegativeInf(ceil32(-math.inf(f32)))); + expect(math.isNan(ceil32(math.nan(f32)))); } test "math.ceil64.special" { - assert(ceil64(0.0) == 0.0); - assert(ceil64(-0.0) == -0.0); - assert(math.isPositiveInf(ceil64(math.inf(f64)))); - assert(math.isNegativeInf(ceil64(-math.inf(f64)))); - assert(math.isNan(ceil64(math.nan(f64)))); + expect(ceil64(0.0) == 0.0); + expect(ceil64(-0.0) == -0.0); + expect(math.isPositiveInf(ceil64(math.inf(f64)))); + expect(math.isNegativeInf(ceil64(-math.inf(f64)))); + expect(math.isNan(ceil64(math.nan(f64)))); } diff --git a/std/math/complex/abs.zig b/std/math/complex/abs.zig index 4cd095c46b..245d67d4c5 100644 --- a/std/math/complex/abs.zig +++ b/std/math/complex/abs.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -14,5 +14,5 @@ const epsilon = 0.0001; test "complex.cabs" { const a = Complex(f32).new(5, 3); const c = abs(a); - debug.assert(math.approxEq(f32, c, 5.83095, epsilon)); + testing.expect(math.approxEq(f32, c, 5.83095, epsilon)); } diff --git a/std/math/complex/acos.zig b/std/math/complex/acos.zig index a5760b4ace..1b314bc31a 100644 --- a/std/math/complex/acos.zig +++ b/std/math/complex/acos.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.cacos" { const a = Complex(f32).new(5, 3); const c = acos(a); - debug.assert(math.approxEq(f32, c.re, 0.546975, epsilon)); - debug.assert(math.approxEq(f32, c.im, -2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.546975, epsilon)); + testing.expect(math.approxEq(f32, c.im, -2.452914, epsilon)); } diff --git a/std/math/complex/acosh.zig b/std/math/complex/acosh.zig index 8dd91b2836..0e4c0121f4 100644 --- a/std/math/complex/acosh.zig +++ b/std/math/complex/acosh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.cacosh" { const a = Complex(f32).new(5, 3); const c = acosh(a); - debug.assert(math.approxEq(f32, c.re, 2.452914, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.546975, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.546975, epsilon)); } diff --git a/std/math/complex/arg.zig b/std/math/complex/arg.zig index f24512ac73..be117a5940 100644 --- a/std/math/complex/arg.zig +++ b/std/math/complex/arg.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -14,5 +14,5 @@ const epsilon = 0.0001; test "complex.carg" { const a = Complex(f32).new(5, 3); const c = arg(a); - debug.assert(math.approxEq(f32, c, 0.540420, epsilon)); + testing.expect(math.approxEq(f32, c, 0.540420, epsilon)); } diff --git a/std/math/complex/asin.zig b/std/math/complex/asin.zig index 584a3a1a9b..cf802ea206 100644 --- a/std/math/complex/asin.zig +++ b/std/math/complex/asin.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -22,6 +22,6 @@ test "complex.casin" { const a = Complex(f32).new(5, 3); const c = asin(a); - debug.assert(math.approxEq(f32, c.re, 1.023822, epsilon)); - debug.assert(math.approxEq(f32, c.im, 2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.023822, epsilon)); + testing.expect(math.approxEq(f32, c.im, 2.452914, epsilon)); } diff --git a/std/math/complex/asinh.zig b/std/math/complex/asinh.zig index 0c4dc2b6e4..0386a636b0 100644 --- a/std/math/complex/asinh.zig +++ b/std/math/complex/asinh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.casinh" { const a = Complex(f32).new(5, 3); const c = asinh(a); - debug.assert(math.approxEq(f32, c.re, 2.459831, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.533999, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.459831, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.533999, epsilon)); } diff --git a/std/math/complex/atan.zig b/std/math/complex/atan.zig index de60f2546d..8e60e58e43 100644 --- a/std/math/complex/atan.zig +++ b/std/math/complex/atan.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -117,14 +117,14 @@ test "complex.catan32" { const a = Complex(f32).new(5, 3); const c = atan(a); - debug.assert(math.approxEq(f32, c.re, 1.423679, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.086569, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.423679, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.086569, epsilon)); } test "complex.catan64" { const a = Complex(f64).new(5, 3); const c = atan(a); - debug.assert(math.approxEq(f64, c.re, 1.423679, epsilon)); - debug.assert(math.approxEq(f64, c.im, 0.086569, epsilon)); + testing.expect(math.approxEq(f64, c.re, 1.423679, epsilon)); + testing.expect(math.approxEq(f64, c.im, 0.086569, epsilon)); } diff --git a/std/math/complex/atanh.zig b/std/math/complex/atanh.zig index f70c741765..5b18fe1992 100644 --- a/std/math/complex/atanh.zig +++ b/std/math/complex/atanh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.catanh" { const a = Complex(f32).new(5, 3); const c = atanh(a); - debug.assert(math.approxEq(f32, c.re, 0.146947, epsilon)); - debug.assert(math.approxEq(f32, c.im, 1.480870, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.146947, epsilon)); + testing.expect(math.approxEq(f32, c.im, 1.480870, epsilon)); } diff --git a/std/math/complex/conj.zig b/std/math/complex/conj.zig index ad3e8b5036..143543f9e7 100644 --- a/std/math/complex/conj.zig +++ b/std/math/complex/conj.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -13,5 +13,5 @@ test "complex.conj" { const a = Complex(f32).new(5, 3); const c = a.conjugate(); - debug.assert(c.re == 5 and c.im == -3); + testing.expect(c.re == 5 and c.im == -3); } diff --git a/std/math/complex/cos.zig b/std/math/complex/cos.zig index 96e4ffcdb0..658d19c3b6 100644 --- a/std/math/complex/cos.zig +++ b/std/math/complex/cos.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.ccos" { const a = Complex(f32).new(5, 3); const c = cos(a); - debug.assert(math.approxEq(f32, c.re, 2.855815, epsilon)); - debug.assert(math.approxEq(f32, c.im, 9.606383, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.855815, epsilon)); + testing.expect(math.approxEq(f32, c.im, 9.606383, epsilon)); } diff --git a/std/math/complex/cosh.zig b/std/math/complex/cosh.zig index 91875a0c47..5ce10b03f8 100644 --- a/std/math/complex/cosh.zig +++ b/std/math/complex/cosh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -152,14 +152,14 @@ test "complex.ccosh32" { const a = Complex(f32).new(5, 3); const c = cosh(a); - debug.assert(math.approxEq(f32, c.re, -73.467300, epsilon)); - debug.assert(math.approxEq(f32, c.im, 10.471557, epsilon)); + testing.expect(math.approxEq(f32, c.re, -73.467300, epsilon)); + testing.expect(math.approxEq(f32, c.im, 10.471557, epsilon)); } test "complex.ccosh64" { const a = Complex(f64).new(5, 3); const c = cosh(a); - debug.assert(math.approxEq(f64, c.re, -73.467300, epsilon)); - debug.assert(math.approxEq(f64, c.im, 10.471557, epsilon)); + testing.expect(math.approxEq(f64, c.re, -73.467300, epsilon)); + testing.expect(math.approxEq(f64, c.im, 10.471557, epsilon)); } diff --git a/std/math/complex/exp.zig b/std/math/complex/exp.zig index 0473f653b6..9ded698d08 100644 --- a/std/math/complex/exp.zig +++ b/std/math/complex/exp.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -118,14 +118,14 @@ test "complex.cexp32" { const a = Complex(f32).new(5, 3); const c = exp(a); - debug.assert(math.approxEq(f32, c.re, -146.927917, epsilon)); - debug.assert(math.approxEq(f32, c.im, 20.944065, epsilon)); + testing.expect(math.approxEq(f32, c.re, -146.927917, epsilon)); + testing.expect(math.approxEq(f32, c.im, 20.944065, epsilon)); } test "complex.cexp64" { const a = Complex(f64).new(5, 3); const c = exp(a); - debug.assert(math.approxEq(f64, c.re, -146.927917, epsilon)); - debug.assert(math.approxEq(f64, c.im, 20.944065, epsilon)); + testing.expect(math.approxEq(f64, c.re, -146.927917, epsilon)); + testing.expect(math.approxEq(f64, c.im, 20.944065, epsilon)); } diff --git a/std/math/complex/index.zig b/std/math/complex/index.zig index 171c4c5829..ffbf14d83e 100644 --- a/std/math/complex/index.zig +++ b/std/math/complex/index.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; pub const abs = @import("abs.zig").abs; @@ -97,7 +97,7 @@ test "complex.add" { const b = Complex(f32).new(2, 7); const c = a.add(b); - debug.assert(c.re == 7 and c.im == 10); + testing.expect(c.re == 7 and c.im == 10); } test "complex.sub" { @@ -105,7 +105,7 @@ test "complex.sub" { const b = Complex(f32).new(2, 7); const c = a.sub(b); - debug.assert(c.re == 3 and c.im == -4); + testing.expect(c.re == 3 and c.im == -4); } test "complex.mul" { @@ -113,7 +113,7 @@ test "complex.mul" { const b = Complex(f32).new(2, 7); const c = a.mul(b); - debug.assert(c.re == -11 and c.im == 41); + testing.expect(c.re == -11 and c.im == 41); } test "complex.div" { @@ -121,7 +121,7 @@ test "complex.div" { const b = Complex(f32).new(2, 7); const c = a.div(b); - debug.assert(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and + testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and math.approxEq(f32, c.im, f32(-29) / 53, epsilon)); } @@ -129,14 +129,14 @@ test "complex.conjugate" { const a = Complex(f32).new(5, 3); const c = a.conjugate(); - debug.assert(c.re == 5 and c.im == -3); + testing.expect(c.re == 5 and c.im == -3); } test "complex.reciprocal" { const a = Complex(f32).new(5, 3); const c = a.reciprocal(); - debug.assert(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and + testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and math.approxEq(f32, c.im, f32(-3) / 34, epsilon)); } @@ -144,7 +144,7 @@ test "complex.magnitude" { const a = Complex(f32).new(5, 3); const c = a.magnitude(); - debug.assert(math.approxEq(f32, c, 5.83095, epsilon)); + testing.expect(math.approxEq(f32, c, 5.83095, epsilon)); } test "complex.cmath" { diff --git a/std/math/complex/log.zig b/std/math/complex/log.zig index a4a1d1664f..360bb7d21e 100644 --- a/std/math/complex/log.zig +++ b/std/math/complex/log.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -18,6 +18,6 @@ test "complex.clog" { const a = Complex(f32).new(5, 3); const c = log(a); - debug.assert(math.approxEq(f32, c.re, 1.763180, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.540419, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.763180, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.540419, epsilon)); } diff --git a/std/math/complex/pow.zig b/std/math/complex/pow.zig index edf68653b6..bd625626c8 100644 --- a/std/math/complex/pow.zig +++ b/std/math/complex/pow.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.cpow" { const b = Complex(f32).new(2.3, -1.3); const c = pow(Complex(f32), a, b); - debug.assert(math.approxEq(f32, c.re, 58.049110, epsilon)); - debug.assert(math.approxEq(f32, c.im, -101.003433, epsilon)); + testing.expect(math.approxEq(f32, c.re, 58.049110, epsilon)); + testing.expect(math.approxEq(f32, c.im, -101.003433, epsilon)); } diff --git a/std/math/complex/proj.zig b/std/math/complex/proj.zig index b6c4cc046e..d31006129e 100644 --- a/std/math/complex/proj.zig +++ b/std/math/complex/proj.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -20,5 +20,5 @@ test "complex.cproj" { const a = Complex(f32).new(5, 3); const c = proj(a); - debug.assert(c.re == 5 and c.im == 3); + testing.expect(c.re == 5 and c.im == 3); } diff --git a/std/math/complex/sin.zig b/std/math/complex/sin.zig index d32b771d3b..9d54ab0969 100644 --- a/std/math/complex/sin.zig +++ b/std/math/complex/sin.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.csin" { const a = Complex(f32).new(5, 3); const c = sin(a); - debug.assert(math.approxEq(f32, c.re, -9.654126, epsilon)); - debug.assert(math.approxEq(f32, c.im, 2.841692, epsilon)); + testing.expect(math.approxEq(f32, c.re, -9.654126, epsilon)); + testing.expect(math.approxEq(f32, c.im, 2.841692, epsilon)); } diff --git a/std/math/complex/sinh.zig b/std/math/complex/sinh.zig index dc19a0ba1b..469ea6067a 100644 --- a/std/math/complex/sinh.zig +++ b/std/math/complex/sinh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -151,14 +151,14 @@ test "complex.csinh32" { const a = Complex(f32).new(5, 3); const c = sinh(a); - debug.assert(math.approxEq(f32, c.re, -73.460617, epsilon)); - debug.assert(math.approxEq(f32, c.im, 10.472508, epsilon)); + testing.expect(math.approxEq(f32, c.re, -73.460617, epsilon)); + testing.expect(math.approxEq(f32, c.im, 10.472508, epsilon)); } test "complex.csinh64" { const a = Complex(f64).new(5, 3); const c = sinh(a); - debug.assert(math.approxEq(f64, c.re, -73.460617, epsilon)); - debug.assert(math.approxEq(f64, c.im, 10.472508, epsilon)); + testing.expect(math.approxEq(f64, c.re, -73.460617, epsilon)); + testing.expect(math.approxEq(f64, c.im, 10.472508, epsilon)); } diff --git a/std/math/complex/sqrt.zig b/std/math/complex/sqrt.zig index 47367816f7..60f6061baa 100644 --- a/std/math/complex/sqrt.zig +++ b/std/math/complex/sqrt.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -125,14 +125,14 @@ test "complex.csqrt32" { const a = Complex(f32).new(5, 3); const c = sqrt(a); - debug.assert(math.approxEq(f32, c.re, 2.327117, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.644574, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.327117, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.644574, epsilon)); } test "complex.csqrt64" { const a = Complex(f64).new(5, 3); const c = sqrt(a); - debug.assert(math.approxEq(f64, c.re, 2.3271175190399496, epsilon)); - debug.assert(math.approxEq(f64, c.im, 0.6445742373246469, epsilon)); + testing.expect(math.approxEq(f64, c.re, 2.3271175190399496, epsilon)); + testing.expect(math.approxEq(f64, c.im, 0.6445742373246469, epsilon)); } diff --git a/std/math/complex/tan.zig b/std/math/complex/tan.zig index 4ea5182fa7..db34580598 100644 --- a/std/math/complex/tan.zig +++ b/std/math/complex/tan.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.ctan" { const a = Complex(f32).new(5, 3); const c = tan(a); - debug.assert(math.approxEq(f32, c.re, -0.002708233, epsilon)); - debug.assert(math.approxEq(f32, c.im, 1.004165, epsilon)); + testing.expect(math.approxEq(f32, c.re, -0.002708233, epsilon)); + testing.expect(math.approxEq(f32, c.im, 1.004165, epsilon)); } diff --git a/std/math/complex/tanh.zig b/std/math/complex/tanh.zig index e48d438783..03ab431312 100644 --- a/std/math/complex/tanh.zig +++ b/std/math/complex/tanh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -100,14 +100,14 @@ test "complex.ctanh32" { const a = Complex(f32).new(5, 3); const c = tanh(a); - debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon)); - debug.assert(math.approxEq(f32, c.im, -0.000025, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.999913, epsilon)); + testing.expect(math.approxEq(f32, c.im, -0.000025, epsilon)); } test "complex.ctanh64" { const a = Complex(f64).new(5, 3); const c = tanh(a); - debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon)); - debug.assert(math.approxEq(f64, c.im, -0.000025, epsilon)); + testing.expect(math.approxEq(f64, c.re, 0.999913, epsilon)); + testing.expect(math.approxEq(f64, c.im, -0.000025, epsilon)); } diff --git a/std/math/copysign.zig b/std/math/copysign.zig index 4c6e333d6c..dbf8f6e1ef 100644 --- a/std/math/copysign.zig +++ b/std/math/copysign.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn copysign(comptime T: type, x: T, y: T) T { @@ -40,28 +40,28 @@ fn copysign64(x: f64, y: f64) f64 { } test "math.copysign" { - assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0)); - assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); - assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); + expect(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0)); + expect(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); + expect(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); } test "math.copysign16" { - assert(copysign16(5.0, 1.0) == 5.0); - assert(copysign16(5.0, -1.0) == -5.0); - assert(copysign16(-5.0, -1.0) == -5.0); - assert(copysign16(-5.0, 1.0) == 5.0); + expect(copysign16(5.0, 1.0) == 5.0); + expect(copysign16(5.0, -1.0) == -5.0); + expect(copysign16(-5.0, -1.0) == -5.0); + expect(copysign16(-5.0, 1.0) == 5.0); } test "math.copysign32" { - assert(copysign32(5.0, 1.0) == 5.0); - assert(copysign32(5.0, -1.0) == -5.0); - assert(copysign32(-5.0, -1.0) == -5.0); - assert(copysign32(-5.0, 1.0) == 5.0); + expect(copysign32(5.0, 1.0) == 5.0); + expect(copysign32(5.0, -1.0) == -5.0); + expect(copysign32(-5.0, -1.0) == -5.0); + expect(copysign32(-5.0, 1.0) == 5.0); } test "math.copysign64" { - assert(copysign64(5.0, 1.0) == 5.0); - assert(copysign64(5.0, -1.0) == -5.0); - assert(copysign64(-5.0, -1.0) == -5.0); - assert(copysign64(-5.0, 1.0) == 5.0); + expect(copysign64(5.0, 1.0) == 5.0); + expect(copysign64(5.0, -1.0) == -5.0); + expect(copysign64(-5.0, -1.0) == -5.0); + expect(copysign64(-5.0, 1.0) == 5.0); } diff --git a/std/math/cos.zig b/std/math/cos.zig index b6a2fbffe6..7783ddc09b 100644 --- a/std/math/cos.zig +++ b/std/math/cos.zig @@ -6,7 +6,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn cos(x: var) @typeOf(x) { const T = @typeOf(x); @@ -139,40 +139,40 @@ fn cos64(x_: f64) f64 { } test "math.cos" { - assert(cos(f32(0.0)) == cos32(0.0)); - assert(cos(f64(0.0)) == cos64(0.0)); + expect(cos(f32(0.0)) == cos32(0.0)); + expect(cos(f64(0.0)) == cos64(0.0)); } test "math.cos32" { const epsilon = 0.000001; - assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); - assert(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); - assert(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); - assert(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); - assert(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); - assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); + expect(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); + expect(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); + expect(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); + expect(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); + expect(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); + expect(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); } test "math.cos64" { const epsilon = 0.000001; - assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); - assert(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); - assert(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); - assert(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); - assert(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); - assert(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); + expect(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); + expect(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); + expect(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); + expect(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); + expect(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); + expect(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); } test "math.cos32.special" { - assert(math.isNan(cos32(math.inf(f32)))); - assert(math.isNan(cos32(-math.inf(f32)))); - assert(math.isNan(cos32(math.nan(f32)))); + expect(math.isNan(cos32(math.inf(f32)))); + expect(math.isNan(cos32(-math.inf(f32)))); + expect(math.isNan(cos32(math.nan(f32)))); } test "math.cos64.special" { - assert(math.isNan(cos64(math.inf(f64)))); - assert(math.isNan(cos64(-math.inf(f64)))); - assert(math.isNan(cos64(math.nan(f64)))); + expect(math.isNan(cos64(math.inf(f64)))); + expect(math.isNan(cos64(-math.inf(f64)))); + expect(math.isNan(cos64(math.nan(f64)))); } diff --git a/std/math/cosh.zig b/std/math/cosh.zig index 77e02855fd..57c5eef828 100644 --- a/std/math/cosh.zig +++ b/std/math/cosh.zig @@ -8,7 +8,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; const expo2 = @import("expo2.zig").expo2; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn cosh(x: var) @typeOf(x) { @@ -82,40 +82,40 @@ fn cosh64(x: f64) f64 { } test "math.cosh" { - assert(cosh(f32(1.5)) == cosh32(1.5)); - assert(cosh(f64(1.5)) == cosh64(1.5)); + expect(cosh(f32(1.5)) == cosh32(1.5)); + expect(cosh(f64(1.5)) == cosh64(1.5)); } test "math.cosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, cosh32(0.0), 1.0, epsilon)); - assert(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon)); - assert(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon)); + expect(math.approxEq(f32, cosh32(0.0), 1.0, epsilon)); + expect(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon)); + expect(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon)); + expect(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon)); } test "math.cosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, cosh64(0.0), 1.0, epsilon)); - assert(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon)); - assert(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon)); + expect(math.approxEq(f64, cosh64(0.0), 1.0, epsilon)); + expect(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon)); + expect(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon)); + expect(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon)); } test "math.cosh32.special" { - assert(cosh32(0.0) == 1.0); - assert(cosh32(-0.0) == 1.0); - assert(math.isPositiveInf(cosh32(math.inf(f32)))); - assert(math.isPositiveInf(cosh32(-math.inf(f32)))); - assert(math.isNan(cosh32(math.nan(f32)))); + expect(cosh32(0.0) == 1.0); + expect(cosh32(-0.0) == 1.0); + expect(math.isPositiveInf(cosh32(math.inf(f32)))); + expect(math.isPositiveInf(cosh32(-math.inf(f32)))); + expect(math.isNan(cosh32(math.nan(f32)))); } test "math.cosh64.special" { - assert(cosh64(0.0) == 1.0); - assert(cosh64(-0.0) == 1.0); - assert(math.isPositiveInf(cosh64(math.inf(f64)))); - assert(math.isPositiveInf(cosh64(-math.inf(f64)))); - assert(math.isNan(cosh64(math.nan(f64)))); + expect(cosh64(0.0) == 1.0); + expect(cosh64(-0.0) == 1.0); + expect(math.isPositiveInf(cosh64(math.inf(f64)))); + expect(math.isPositiveInf(cosh64(-math.inf(f64)))); + expect(math.isNan(cosh64(math.nan(f64)))); } diff --git a/std/math/exp2.zig b/std/math/exp2.zig index 3d8e5d692e..ba0001a09a 100644 --- a/std/math/exp2.zig +++ b/std/math/exp2.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn exp2(x: var) @typeOf(x) { const T = @typeOf(x); @@ -415,35 +415,35 @@ fn exp2_64(x: f64) f64 { } test "math.exp2" { - assert(exp2(f32(0.8923)) == exp2_32(0.8923)); - assert(exp2(f64(0.8923)) == exp2_64(0.8923)); + expect(exp2(f32(0.8923)) == exp2_32(0.8923)); + expect(exp2(f64(0.8923)) == exp2_64(0.8923)); } test "math.exp2_32" { const epsilon = 0.000001; - assert(exp2_32(0.0) == 1.0); - assert(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon)); - assert(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon)); - assert(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon)); + expect(exp2_32(0.0) == 1.0); + expect(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon)); + expect(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon)); + expect(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon)); + expect(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon)); } test "math.exp2_64" { const epsilon = 0.000001; - assert(exp2_64(0.0) == 1.0); - assert(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon)); - assert(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon)); + expect(exp2_64(0.0) == 1.0); + expect(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon)); + expect(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon)); + expect(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon)); } test "math.exp2_32.special" { - assert(math.isPositiveInf(exp2_32(math.inf(f32)))); - assert(math.isNan(exp2_32(math.nan(f32)))); + expect(math.isPositiveInf(exp2_32(math.inf(f32)))); + expect(math.isNan(exp2_32(math.nan(f32)))); } test "math.exp2_64.special" { - assert(math.isPositiveInf(exp2_64(math.inf(f64)))); - assert(math.isNan(exp2_64(math.nan(f64)))); + expect(math.isPositiveInf(exp2_64(math.inf(f64)))); + expect(math.isNan(exp2_64(math.nan(f64)))); } diff --git a/std/math/expm1.zig b/std/math/expm1.zig index 6729417f60..ba00ec2561 100644 --- a/std/math/expm1.zig +++ b/std/math/expm1.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn expm1(x: var) @typeOf(x) { const T = @typeOf(x); @@ -278,42 +278,42 @@ fn expm1_64(x_: f64) f64 { } test "math.exp1m" { - assert(expm1(f32(0.0)) == expm1_32(0.0)); - assert(expm1(f64(0.0)) == expm1_64(0.0)); + expect(expm1(f32(0.0)) == expm1_32(0.0)); + expect(expm1(f64(0.0)) == expm1_64(0.0)); } test "math.expm1_32" { const epsilon = 0.000001; - assert(expm1_32(0.0) == 0.0); - assert(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon)); - assert(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon)); + expect(expm1_32(0.0) == 0.0); + expect(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon)); + expect(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon)); + expect(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon)); } test "math.expm1_64" { const epsilon = 0.000001; - assert(expm1_64(0.0) == 0.0); - assert(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon)); - assert(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon)); + expect(expm1_64(0.0) == 0.0); + expect(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon)); + expect(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon)); + expect(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon)); } test "math.expm1_32.special" { const epsilon = 0.000001; - assert(math.isPositiveInf(expm1_32(math.inf(f32)))); - assert(expm1_32(-math.inf(f32)) == -1.0); - assert(math.isNan(expm1_32(math.nan(f32)))); + expect(math.isPositiveInf(expm1_32(math.inf(f32)))); + expect(expm1_32(-math.inf(f32)) == -1.0); + expect(math.isNan(expm1_32(math.nan(f32)))); } test "math.expm1_64.special" { const epsilon = 0.000001; - assert(math.isPositiveInf(expm1_64(math.inf(f64)))); - assert(expm1_64(-math.inf(f64)) == -1.0); - assert(math.isNan(expm1_64(math.nan(f64)))); + expect(math.isPositiveInf(expm1_64(math.inf(f64)))); + expect(expm1_64(-math.inf(f64)) == -1.0); + expect(math.isNan(expm1_64(math.nan(f64)))); } diff --git a/std/math/fabs.zig b/std/math/fabs.zig index 443010ac7f..9fad5644c3 100644 --- a/std/math/fabs.zig +++ b/std/math/fabs.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn fabs(x: var) @typeOf(x) { @@ -37,40 +37,40 @@ fn fabs64(x: f64) f64 { } test "math.fabs" { - assert(fabs(f16(1.0)) == fabs16(1.0)); - assert(fabs(f32(1.0)) == fabs32(1.0)); - assert(fabs(f64(1.0)) == fabs64(1.0)); + expect(fabs(f16(1.0)) == fabs16(1.0)); + expect(fabs(f32(1.0)) == fabs32(1.0)); + expect(fabs(f64(1.0)) == fabs64(1.0)); } test "math.fabs16" { - assert(fabs16(1.0) == 1.0); - assert(fabs16(-1.0) == 1.0); + expect(fabs16(1.0) == 1.0); + expect(fabs16(-1.0) == 1.0); } test "math.fabs32" { - assert(fabs32(1.0) == 1.0); - assert(fabs32(-1.0) == 1.0); + expect(fabs32(1.0) == 1.0); + expect(fabs32(-1.0) == 1.0); } test "math.fabs64" { - assert(fabs64(1.0) == 1.0); - assert(fabs64(-1.0) == 1.0); + expect(fabs64(1.0) == 1.0); + expect(fabs64(-1.0) == 1.0); } test "math.fabs16.special" { - assert(math.isPositiveInf(fabs(math.inf(f16)))); - assert(math.isPositiveInf(fabs(-math.inf(f16)))); - assert(math.isNan(fabs(math.nan(f16)))); + expect(math.isPositiveInf(fabs(math.inf(f16)))); + expect(math.isPositiveInf(fabs(-math.inf(f16)))); + expect(math.isNan(fabs(math.nan(f16)))); } test "math.fabs32.special" { - assert(math.isPositiveInf(fabs(math.inf(f32)))); - assert(math.isPositiveInf(fabs(-math.inf(f32)))); - assert(math.isNan(fabs(math.nan(f32)))); + expect(math.isPositiveInf(fabs(math.inf(f32)))); + expect(math.isPositiveInf(fabs(-math.inf(f32)))); + expect(math.isNan(fabs(math.nan(f32)))); } test "math.fabs64.special" { - assert(math.isPositiveInf(fabs(math.inf(f64)))); - assert(math.isPositiveInf(fabs(-math.inf(f64)))); - assert(math.isNan(fabs(math.nan(f64)))); + expect(math.isPositiveInf(fabs(math.inf(f64)))); + expect(math.isPositiveInf(fabs(-math.inf(f64)))); + expect(math.isNan(fabs(math.nan(f64)))); } diff --git a/std/math/floor.zig b/std/math/floor.zig index 6ce462b10f..c7c12e37ba 100644 --- a/std/math/floor.zig +++ b/std/math/floor.zig @@ -5,7 +5,7 @@ // - floor(nan) = nan const builtin = @import("builtin"); -const assert = std.debug.assert; +const expect = std.testing.expect; const std = @import("../index.zig"); const math = std.math; @@ -117,49 +117,49 @@ fn floor64(x: f64) f64 { } test "math.floor" { - assert(floor(f16(1.3)) == floor16(1.3)); - assert(floor(f32(1.3)) == floor32(1.3)); - assert(floor(f64(1.3)) == floor64(1.3)); + expect(floor(f16(1.3)) == floor16(1.3)); + expect(floor(f32(1.3)) == floor32(1.3)); + expect(floor(f64(1.3)) == floor64(1.3)); } test "math.floor16" { - assert(floor16(1.3) == 1.0); - assert(floor16(-1.3) == -2.0); - assert(floor16(0.2) == 0.0); + expect(floor16(1.3) == 1.0); + expect(floor16(-1.3) == -2.0); + expect(floor16(0.2) == 0.0); } test "math.floor32" { - assert(floor32(1.3) == 1.0); - assert(floor32(-1.3) == -2.0); - assert(floor32(0.2) == 0.0); + expect(floor32(1.3) == 1.0); + expect(floor32(-1.3) == -2.0); + expect(floor32(0.2) == 0.0); } test "math.floor64" { - assert(floor64(1.3) == 1.0); - assert(floor64(-1.3) == -2.0); - assert(floor64(0.2) == 0.0); + expect(floor64(1.3) == 1.0); + expect(floor64(-1.3) == -2.0); + expect(floor64(0.2) == 0.0); } test "math.floor16.special" { - assert(floor16(0.0) == 0.0); - assert(floor16(-0.0) == -0.0); - assert(math.isPositiveInf(floor16(math.inf(f16)))); - assert(math.isNegativeInf(floor16(-math.inf(f16)))); - assert(math.isNan(floor16(math.nan(f16)))); + expect(floor16(0.0) == 0.0); + expect(floor16(-0.0) == -0.0); + expect(math.isPositiveInf(floor16(math.inf(f16)))); + expect(math.isNegativeInf(floor16(-math.inf(f16)))); + expect(math.isNan(floor16(math.nan(f16)))); } test "math.floor32.special" { - assert(floor32(0.0) == 0.0); - assert(floor32(-0.0) == -0.0); - assert(math.isPositiveInf(floor32(math.inf(f32)))); - assert(math.isNegativeInf(floor32(-math.inf(f32)))); - assert(math.isNan(floor32(math.nan(f32)))); + expect(floor32(0.0) == 0.0); + expect(floor32(-0.0) == -0.0); + expect(math.isPositiveInf(floor32(math.inf(f32)))); + expect(math.isNegativeInf(floor32(-math.inf(f32)))); + expect(math.isNan(floor32(math.nan(f32)))); } test "math.floor64.special" { - assert(floor64(0.0) == 0.0); - assert(floor64(-0.0) == -0.0); - assert(math.isPositiveInf(floor64(math.inf(f64)))); - assert(math.isNegativeInf(floor64(-math.inf(f64)))); - assert(math.isNan(floor64(math.nan(f64)))); + expect(floor64(0.0) == 0.0); + expect(floor64(-0.0) == -0.0); + expect(math.isPositiveInf(floor64(math.inf(f64)))); + expect(math.isNegativeInf(floor64(-math.inf(f64)))); + expect(math.isNan(floor64(math.nan(f64)))); } diff --git a/std/math/fma.zig b/std/math/fma.zig index 21faf4118d..b084cf3cbd 100644 --- a/std/math/fma.zig +++ b/std/math/fma.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn fma(comptime T: type, x: T, y: T, z: T) T { return switch (T) { @@ -135,30 +135,30 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { } test "math.fma" { - assert(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); - assert(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); + expect(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); + expect(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); } test "math.fma32" { const epsilon = 0.000001; - assert(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); - assert(math.approxEq(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon)); - assert(math.approxEq(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon)); - assert(math.approxEq(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon)); - assert(math.approxEq(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon)); - assert(math.approxEq(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon)); - assert(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + expect(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); + expect(math.approxEq(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon)); + expect(math.approxEq(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon)); + expect(math.approxEq(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon)); + expect(math.approxEq(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon)); + expect(math.approxEq(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon)); + expect(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "math.fma64" { const epsilon = 0.000001; - assert(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); - assert(math.approxEq(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon)); - assert(math.approxEq(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon)); - assert(math.approxEq(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon)); - assert(math.approxEq(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon)); - assert(math.approxEq(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon)); - assert(math.approxEq(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + expect(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); + expect(math.approxEq(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon)); + expect(math.approxEq(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon)); + expect(math.approxEq(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon)); + expect(math.approxEq(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon)); + expect(math.approxEq(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon)); + expect(math.approxEq(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } diff --git a/std/math/frexp.zig b/std/math/frexp.zig index dfc790fdd9..35f3e081a9 100644 --- a/std/math/frexp.zig +++ b/std/math/frexp.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; fn frexp_result(comptime T: type) type { return struct { @@ -103,11 +103,11 @@ fn frexp64(x: f64) frexp64_result { test "math.frexp" { const a = frexp(f32(1.3)); const b = frexp32(1.3); - assert(a.significand == b.significand and a.exponent == b.exponent); + expect(a.significand == b.significand and a.exponent == b.exponent); const c = frexp(f64(1.3)); const d = frexp64(1.3); - assert(c.significand == d.significand and c.exponent == d.exponent); + expect(c.significand == d.significand and c.exponent == d.exponent); } test "math.frexp32" { @@ -115,10 +115,10 @@ test "math.frexp32" { var r: frexp32_result = undefined; r = frexp32(1.3); - assert(math.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1); + expect(math.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp32(78.0234); - assert(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); + expect(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); } test "math.frexp64" { @@ -126,46 +126,46 @@ test "math.frexp64" { var r: frexp64_result = undefined; r = frexp64(1.3); - assert(math.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1); + expect(math.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp64(78.0234); - assert(math.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7); + expect(math.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7); } test "math.frexp32.special" { var r: frexp32_result = undefined; r = frexp32(0.0); - assert(r.significand == 0.0 and r.exponent == 0); + expect(r.significand == 0.0 and r.exponent == 0); r = frexp32(-0.0); - assert(r.significand == -0.0 and r.exponent == 0); + expect(r.significand == -0.0 and r.exponent == 0); r = frexp32(math.inf(f32)); - assert(math.isPositiveInf(r.significand) and r.exponent == 0); + expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp32(-math.inf(f32)); - assert(math.isNegativeInf(r.significand) and r.exponent == 0); + expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp32(math.nan(f32)); - assert(math.isNan(r.significand)); + expect(math.isNan(r.significand)); } test "math.frexp64.special" { var r: frexp64_result = undefined; r = frexp64(0.0); - assert(r.significand == 0.0 and r.exponent == 0); + expect(r.significand == 0.0 and r.exponent == 0); r = frexp64(-0.0); - assert(r.significand == -0.0 and r.exponent == 0); + expect(r.significand == -0.0 and r.exponent == 0); r = frexp64(math.inf(f64)); - assert(math.isPositiveInf(r.significand) and r.exponent == 0); + expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp64(-math.inf(f64)); - assert(math.isNegativeInf(r.significand) and r.exponent == 0); + expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp64(math.nan(f64)); - assert(math.isNan(r.significand)); + expect(math.isNan(r.significand)); } diff --git a/std/math/hypot.zig b/std/math/hypot.zig index a63657a621..dea11e0a61 100644 --- a/std/math/hypot.zig +++ b/std/math/hypot.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn hypot(comptime T: type, x: T, y: T) T { @@ -115,48 +115,48 @@ fn hypot64(x: f64, y: f64) f64 { } test "math.hypot" { - assert(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2)); - assert(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2)); + expect(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2)); + expect(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2)); } test "math.hypot32" { const epsilon = 0.000001; - assert(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon)); - assert(math.approxEq(f32, hypot32(0.2, -0.34), 0.394462, epsilon)); - assert(math.approxEq(f32, hypot32(0.8923, 2.636890), 2.783772, epsilon)); - assert(math.approxEq(f32, hypot32(1.5, 5.25), 5.460083, epsilon)); - assert(math.approxEq(f32, hypot32(37.45, 159.835), 164.163742, epsilon)); - assert(math.approxEq(f32, hypot32(89.123, 382.028905), 392.286865, epsilon)); - assert(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon)); + expect(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon)); + expect(math.approxEq(f32, hypot32(0.2, -0.34), 0.394462, epsilon)); + expect(math.approxEq(f32, hypot32(0.8923, 2.636890), 2.783772, epsilon)); + expect(math.approxEq(f32, hypot32(1.5, 5.25), 5.460083, epsilon)); + expect(math.approxEq(f32, hypot32(37.45, 159.835), 164.163742, epsilon)); + expect(math.approxEq(f32, hypot32(89.123, 382.028905), 392.286865, epsilon)); + expect(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon)); } test "math.hypot64" { const epsilon = 0.000001; - assert(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon)); - assert(math.approxEq(f64, hypot64(0.2, -0.34), 0.394462, epsilon)); - assert(math.approxEq(f64, hypot64(0.8923, 2.636890), 2.783772, epsilon)); - assert(math.approxEq(f64, hypot64(1.5, 5.25), 5.460082, epsilon)); - assert(math.approxEq(f64, hypot64(37.45, 159.835), 164.163728, epsilon)); - assert(math.approxEq(f64, hypot64(89.123, 382.028905), 392.286876, epsilon)); - assert(math.approxEq(f64, hypot64(123123.234375, 529428.707813), 543556.885247, epsilon)); + expect(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon)); + expect(math.approxEq(f64, hypot64(0.2, -0.34), 0.394462, epsilon)); + expect(math.approxEq(f64, hypot64(0.8923, 2.636890), 2.783772, epsilon)); + expect(math.approxEq(f64, hypot64(1.5, 5.25), 5.460082, epsilon)); + expect(math.approxEq(f64, hypot64(37.45, 159.835), 164.163728, epsilon)); + expect(math.approxEq(f64, hypot64(89.123, 382.028905), 392.286876, epsilon)); + expect(math.approxEq(f64, hypot64(123123.234375, 529428.707813), 543556.885247, epsilon)); } test "math.hypot32.special" { - assert(math.isPositiveInf(hypot32(math.inf(f32), 0.0))); - assert(math.isPositiveInf(hypot32(-math.inf(f32), 0.0))); - assert(math.isPositiveInf(hypot32(0.0, math.inf(f32)))); - assert(math.isPositiveInf(hypot32(0.0, -math.inf(f32)))); - assert(math.isNan(hypot32(math.nan(f32), 0.0))); - assert(math.isNan(hypot32(0.0, math.nan(f32)))); + expect(math.isPositiveInf(hypot32(math.inf(f32), 0.0))); + expect(math.isPositiveInf(hypot32(-math.inf(f32), 0.0))); + expect(math.isPositiveInf(hypot32(0.0, math.inf(f32)))); + expect(math.isPositiveInf(hypot32(0.0, -math.inf(f32)))); + expect(math.isNan(hypot32(math.nan(f32), 0.0))); + expect(math.isNan(hypot32(0.0, math.nan(f32)))); } test "math.hypot64.special" { - assert(math.isPositiveInf(hypot64(math.inf(f64), 0.0))); - assert(math.isPositiveInf(hypot64(-math.inf(f64), 0.0))); - assert(math.isPositiveInf(hypot64(0.0, math.inf(f64)))); - assert(math.isPositiveInf(hypot64(0.0, -math.inf(f64)))); - assert(math.isNan(hypot64(math.nan(f64), 0.0))); - assert(math.isNan(hypot64(0.0, math.nan(f64)))); + expect(math.isPositiveInf(hypot64(math.inf(f64), 0.0))); + expect(math.isPositiveInf(hypot64(-math.inf(f64), 0.0))); + expect(math.isPositiveInf(hypot64(0.0, math.inf(f64)))); + expect(math.isPositiveInf(hypot64(0.0, -math.inf(f64)))); + expect(math.isNan(hypot64(math.nan(f64), 0.0))); + expect(math.isNan(hypot64(0.0, math.nan(f64)))); } diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig index e6bdb14012..e7b6485357 100644 --- a/std/math/ilogb.zig +++ b/std/math/ilogb.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -95,38 +95,38 @@ fn ilogb64(x: f64) i32 { } test "math.ilogb" { - assert(ilogb(f32(0.2)) == ilogb32(0.2)); - assert(ilogb(f64(0.2)) == ilogb64(0.2)); + expect(ilogb(f32(0.2)) == ilogb32(0.2)); + expect(ilogb(f64(0.2)) == ilogb64(0.2)); } test "math.ilogb32" { - assert(ilogb32(0.0) == fp_ilogb0); - assert(ilogb32(0.5) == -1); - assert(ilogb32(0.8923) == -1); - assert(ilogb32(10.0) == 3); - assert(ilogb32(-123984) == 16); - assert(ilogb32(2398.23) == 11); + expect(ilogb32(0.0) == fp_ilogb0); + expect(ilogb32(0.5) == -1); + expect(ilogb32(0.8923) == -1); + expect(ilogb32(10.0) == 3); + expect(ilogb32(-123984) == 16); + expect(ilogb32(2398.23) == 11); } test "math.ilogb64" { - assert(ilogb64(0.0) == fp_ilogb0); - assert(ilogb64(0.5) == -1); - assert(ilogb64(0.8923) == -1); - assert(ilogb64(10.0) == 3); - assert(ilogb64(-123984) == 16); - assert(ilogb64(2398.23) == 11); + expect(ilogb64(0.0) == fp_ilogb0); + expect(ilogb64(0.5) == -1); + expect(ilogb64(0.8923) == -1); + expect(ilogb64(10.0) == 3); + expect(ilogb64(-123984) == 16); + expect(ilogb64(2398.23) == 11); } test "math.ilogb32.special" { - assert(ilogb32(math.inf(f32)) == maxInt(i32)); - assert(ilogb32(-math.inf(f32)) == maxInt(i32)); - assert(ilogb32(0.0) == minInt(i32)); - assert(ilogb32(math.nan(f32)) == maxInt(i32)); + expect(ilogb32(math.inf(f32)) == maxInt(i32)); + expect(ilogb32(-math.inf(f32)) == maxInt(i32)); + expect(ilogb32(0.0) == minInt(i32)); + expect(ilogb32(math.nan(f32)) == maxInt(i32)); } test "math.ilogb64.special" { - assert(ilogb64(math.inf(f64)) == maxInt(i32)); - assert(ilogb64(-math.inf(f64)) == maxInt(i32)); - assert(ilogb64(0.0) == minInt(i32)); - assert(ilogb64(math.nan(f64)) == maxInt(i32)); + expect(ilogb64(math.inf(f64)) == maxInt(i32)); + expect(ilogb64(-math.inf(f64)) == maxInt(i32)); + expect(ilogb64(0.0) == minInt(i32)); + expect(ilogb64(math.nan(f64)) == maxInt(i32)); } diff --git a/std/math/index.zig b/std/math/index.zig index f37de2505b..ccfac03038 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -2,6 +2,7 @@ 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; @@ -240,7 +241,7 @@ pub fn min(x: var, y: var) @typeOf(x + y) { } test "math.min" { - assert(min(i32(-1), i32(2)) == -1); + testing.expect(min(i32(-1), i32(2)) == -1); } pub fn max(x: var, y: var) @typeOf(x + y) { @@ -248,7 +249,7 @@ pub fn max(x: var, y: var) @typeOf(x + y) { } test "math.max" { - assert(max(i32(-1), i32(2)) == 2); + testing.expect(max(i32(-1), i32(2)) == 2); } pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { @@ -293,10 +294,10 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T { } test "math.shl" { - assert(shl(u8, 0b11111111, usize(3)) == 0b11111000); - assert(shl(u8, 0b11111111, usize(8)) == 0); - assert(shl(u8, 0b11111111, usize(9)) == 0); - assert(shl(u8, 0b11111111, isize(-2)) == 0b00111111); + 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. @@ -317,10 +318,10 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T { } test "math.shr" { - assert(shr(u8, 0b11111111, usize(3)) == 0b00011111); - assert(shr(u8, 0b11111111, usize(8)) == 0); - assert(shr(u8, 0b11111111, usize(9)) == 0); - assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100); + 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. @@ -335,11 +336,11 @@ pub fn rotr(comptime T: type, x: T, r: var) T { } test "math.rotr" { - assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001); - assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000); - assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001); - assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000); - assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010); + 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. @@ -354,11 +355,11 @@ pub fn rotl(comptime T: type, x: T, r: var) T { } test "math.rotl" { - assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001); - assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010); - assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001); - assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000); - assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000); + 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 { @@ -389,50 +390,50 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t } test "math.IntFittingRange" { - assert(IntFittingRange(0, 0) == u0); - assert(IntFittingRange(0, 1) == u1); - assert(IntFittingRange(0, 2) == u2); - assert(IntFittingRange(0, 3) == u2); - assert(IntFittingRange(0, 4) == u3); - assert(IntFittingRange(0, 7) == u3); - assert(IntFittingRange(0, 8) == u4); - assert(IntFittingRange(0, 9) == u4); - assert(IntFittingRange(0, 15) == u4); - assert(IntFittingRange(0, 16) == u5); - assert(IntFittingRange(0, 17) == u5); - assert(IntFittingRange(0, 4095) == u12); - assert(IntFittingRange(2000, 4095) == u12); - assert(IntFittingRange(0, 4096) == u13); - assert(IntFittingRange(2000, 4096) == u13); - assert(IntFittingRange(0, 4097) == u13); - assert(IntFittingRange(2000, 4097) == u13); - assert(IntFittingRange(0, 123456789123456798123456789) == u87); - assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177); + 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); - assert(IntFittingRange(-1, -1) == i1); - assert(IntFittingRange(-1, 0) == i1); - assert(IntFittingRange(-1, 1) == i2); - assert(IntFittingRange(-2, -2) == i2); - assert(IntFittingRange(-2, -1) == i2); - assert(IntFittingRange(-2, 0) == i2); - assert(IntFittingRange(-2, 1) == i2); - assert(IntFittingRange(-2, 2) == i3); - assert(IntFittingRange(-1, 2) == i3); - assert(IntFittingRange(-1, 3) == i3); - assert(IntFittingRange(-1, 4) == i4); - assert(IntFittingRange(-1, 7) == i4); - assert(IntFittingRange(-1, 8) == i5); - assert(IntFittingRange(-1, 9) == i5); - assert(IntFittingRange(-1, 15) == i5); - assert(IntFittingRange(-1, 16) == i6); - assert(IntFittingRange(-1, 17) == i6); - assert(IntFittingRange(-1, 4095) == i13); - assert(IntFittingRange(-4096, 4095) == i13); - assert(IntFittingRange(-1, 4096) == i14); - assert(IntFittingRange(-4097, 4095) == i14); - assert(IntFittingRange(-1, 4097) == i14); - assert(IntFittingRange(-1, 123456789123456798123456789) == i88); - assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178); + 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" { @@ -441,10 +442,10 @@ test "math overflow functions" { } fn testOverflow() void { - assert((mul(i32, 3, 4) catch unreachable) == 12); - assert((add(i32, 3, 4) catch unreachable) == 7); - assert((sub(i32, 3, 4) catch unreachable) == -1); - assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); + 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) { @@ -465,8 +466,8 @@ test "math.absInt" { comptime testAbsInt(); } fn testAbsInt() void { - assert((absInt(i32(-10)) catch unreachable) == 10); - assert((absInt(i32(10)) catch unreachable) == 10); + testing.expect((absInt(i32(-10)) catch unreachable) == 10); + testing.expect((absInt(i32(10)) catch unreachable) == 10); } pub const absFloat = @import("fabs.zig").fabs; @@ -483,13 +484,13 @@ test "math.divTrunc" { comptime testDivTrunc(); } fn testDivTrunc() void { - assert((divTrunc(i32, 5, 3) catch unreachable) == 1); - assert((divTrunc(i32, -5, 3) catch unreachable) == -1); - if (divTrunc(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divTrunc(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); + 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)); - assert((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0); - assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); + 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 { @@ -504,13 +505,13 @@ test "math.divFloor" { comptime testDivFloor(); } fn testDivFloor() void { - assert((divFloor(i32, 5, 3) catch unreachable) == 1); - assert((divFloor(i32, -5, 3) catch unreachable) == -2); - if (divFloor(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divFloor(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); + 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)); - assert((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0); - assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); + 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 { @@ -527,15 +528,15 @@ test "math.divExact" { comptime testDivExact(); } fn testDivExact() void { - assert((divExact(i32, 10, 5) catch unreachable) == 2); - assert((divExact(i32, -10, 5) catch unreachable) == -2); - if (divExact(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divExact(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); - if (divExact(i32, 5, 2)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); + 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)); - assert((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0); - assert((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0); - if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); + 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 { @@ -550,15 +551,15 @@ test "math.mod" { comptime testMod(); } fn testMod() void { - assert((mod(i32, -5, 3) catch unreachable) == 1); - assert((mod(i32, 5, 3) catch unreachable) == 2); - if (mod(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + 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)); - assert((mod(f32, -5, 3) catch unreachable) == 1); - assert((mod(f32, 5, 3) catch unreachable) == 2); - if (mod(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + 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 { @@ -573,15 +574,15 @@ test "math.rem" { comptime testRem(); } fn testRem() void { - assert((rem(i32, -5, 3) catch unreachable) == -2); - assert((rem(i32, 5, 3) catch unreachable) == 2); - if (rem(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + 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)); - assert((rem(f32, -5, 3) catch unreachable) == -2); - assert((rem(f32, 5, 3) catch unreachable) == 2); - if (rem(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + 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. @@ -594,14 +595,14 @@ pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) { } test "math.absCast" { - assert(absCast(i32(-999)) == 999); - assert(@typeOf(absCast(i32(-999))) == u32); + testing.expect(absCast(i32(-999)) == 999); + testing.expect(@typeOf(absCast(i32(-999))) == u32); - assert(absCast(i32(999)) == 999); - assert(@typeOf(absCast(i32(999))) == u32); + testing.expect(absCast(i32(999)) == 999); + testing.expect(@typeOf(absCast(i32(999))) == u32); - assert(absCast(i32(minInt(i32))) == -minInt(i32)); - assert(@typeOf(absCast(i32(minInt(i32)))) == u32); + testing.expect(absCast(i32(minInt(i32))) == -minInt(i32)); + testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32); } /// Returns the negation of the integer parameter. @@ -618,13 +619,13 @@ pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) { } test "math.negateCast" { - assert((negateCast(u32(999)) catch unreachable) == -999); - assert(@typeOf(negateCast(u32(999)) catch unreachable) == i32); + testing.expect((negateCast(u32(999)) catch unreachable) == -999); + testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32); - assert((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32)); - assert(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32); + testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32)); + testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32); - if (negateCast(u32(maxInt(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow); + testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10))); } /// Cast an integer to a different integer type. If the value doesn't fit, @@ -642,13 +643,13 @@ pub fn cast(comptime T: type, x: var) (error{Overflow}!T) { } test "math.cast" { - if (cast(u8, u32(300))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(i8, i32(-200))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(u8, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(u64, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); + 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))); - assert((try cast(u8, u32(255))) == u8(255)); - assert(@typeOf(try cast(u8, u32(255))) == u8); + testing.expect((try cast(u8, u32(255))) == u8(255)); + testing.expect(@typeOf(try cast(u8, u32(255))) == u8); } pub const AlignCastError = error{UnalignedMemory}; @@ -692,25 +693,25 @@ pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) { } test "std.math.log2_int_ceil" { - assert(log2_int_ceil(u32, 1) == 0); - assert(log2_int_ceil(u32, 2) == 1); - assert(log2_int_ceil(u32, 3) == 2); - assert(log2_int_ceil(u32, 4) == 2); - assert(log2_int_ceil(u32, 5) == 3); - assert(log2_int_ceil(u32, 6) == 3); - assert(log2_int_ceil(u32, 7) == 3); - assert(log2_int_ceil(u32, 8) == 3); - assert(log2_int_ceil(u32, 9) == 4); - assert(log2_int_ceil(u32, 10) == 4); + 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 { - assert(floorPowerOfTwo(u32, 63) == 32); - assert(floorPowerOfTwo(u32, 64) == 64); - assert(floorPowerOfTwo(u32, 65) == 64); - assert(floorPowerOfTwo(u4, 7) == 4); - assert(floorPowerOfTwo(u4, 8) == 8); - assert(floorPowerOfTwo(u4, 9) == 8); + 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 { @@ -726,7 +727,7 @@ pub fn lossyCast(comptime T: type, value: var) T { test "math.f64_min" { const f64_min_u64 = 0x0010000000000000; const fmin: f64 = f64_min; - assert(@bitCast(u64, fmin) == f64_min_u64); + testing.expect(@bitCast(u64, fmin) == f64_min_u64); } pub fn maxInt(comptime T: type) comptime_int { @@ -745,36 +746,36 @@ pub fn minInt(comptime T: type) comptime_int { } test "minInt and maxInt" { - assert(maxInt(u0) == 0); - assert(maxInt(u1) == 1); - assert(maxInt(u8) == 255); - assert(maxInt(u16) == 65535); - assert(maxInt(u32) == 4294967295); - assert(maxInt(u64) == 18446744073709551615); + 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); - assert(maxInt(i0) == 0); - assert(maxInt(i1) == 0); - assert(maxInt(i8) == 127); - assert(maxInt(i16) == 32767); - assert(maxInt(i32) == 2147483647); - assert(maxInt(i63) == 4611686018427387903); - assert(maxInt(i64) == 9223372036854775807); + 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); - assert(minInt(u0) == 0); - assert(minInt(u1) == 0); - assert(minInt(u8) == 0); - assert(minInt(u16) == 0); - assert(minInt(u32) == 0); - assert(minInt(u63) == 0); - assert(minInt(u64) == 0); + 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); - assert(minInt(i0) == 0); - assert(minInt(i1) == -1); - assert(minInt(i8) == -128); - assert(minInt(i16) == -32768); - assert(minInt(i32) == -2147483648); - assert(minInt(i63) == -4611686018427387904); - assert(minInt(i64) == -9223372036854775808); + 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); } test "max value type" { @@ -782,5 +783,5 @@ test "max value type" { // u32 would not work. But since the value is a number literal, // it works fine. const x: u32 = maxInt(i32); - assert(x == 2147483647); + testing.expect(x == 2147483647); } diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig index bdfdff8f9f..bf1c9ac63c 100644 --- a/std/math/isfinite.zig +++ b/std/math/isfinite.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isFinite(x: var) bool { @@ -25,16 +25,16 @@ pub fn isFinite(x: var) bool { } test "math.isFinite" { - assert(isFinite(f16(0.0))); - assert(isFinite(f16(-0.0))); - assert(isFinite(f32(0.0))); - assert(isFinite(f32(-0.0))); - assert(isFinite(f64(0.0))); - assert(isFinite(f64(-0.0))); - assert(!isFinite(math.inf(f16))); - assert(!isFinite(-math.inf(f16))); - assert(!isFinite(math.inf(f32))); - assert(!isFinite(-math.inf(f32))); - assert(!isFinite(math.inf(f64))); - assert(!isFinite(-math.inf(f64))); + expect(isFinite(f16(0.0))); + expect(isFinite(f16(-0.0))); + expect(isFinite(f32(0.0))); + expect(isFinite(f32(-0.0))); + expect(isFinite(f64(0.0))); + expect(isFinite(f64(-0.0))); + expect(!isFinite(math.inf(f16))); + expect(!isFinite(-math.inf(f16))); + expect(!isFinite(math.inf(f32))); + expect(!isFinite(-math.inf(f32))); + expect(!isFinite(math.inf(f64))); + expect(!isFinite(-math.inf(f64))); } diff --git a/std/math/isinf.zig b/std/math/isinf.zig index 93f66cc870..e34e9c5971 100644 --- a/std/math/isinf.zig +++ b/std/math/isinf.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isInf(x: var) bool { @@ -61,46 +61,46 @@ pub fn isNegativeInf(x: var) bool { } test "math.isInf" { - assert(!isInf(f16(0.0))); - assert(!isInf(f16(-0.0))); - assert(!isInf(f32(0.0))); - assert(!isInf(f32(-0.0))); - assert(!isInf(f64(0.0))); - assert(!isInf(f64(-0.0))); - assert(isInf(math.inf(f16))); - assert(isInf(-math.inf(f16))); - assert(isInf(math.inf(f32))); - assert(isInf(-math.inf(f32))); - assert(isInf(math.inf(f64))); - assert(isInf(-math.inf(f64))); + expect(!isInf(f16(0.0))); + expect(!isInf(f16(-0.0))); + expect(!isInf(f32(0.0))); + expect(!isInf(f32(-0.0))); + expect(!isInf(f64(0.0))); + expect(!isInf(f64(-0.0))); + expect(isInf(math.inf(f16))); + expect(isInf(-math.inf(f16))); + expect(isInf(math.inf(f32))); + expect(isInf(-math.inf(f32))); + expect(isInf(math.inf(f64))); + expect(isInf(-math.inf(f64))); } test "math.isPositiveInf" { - assert(!isPositiveInf(f16(0.0))); - assert(!isPositiveInf(f16(-0.0))); - assert(!isPositiveInf(f32(0.0))); - assert(!isPositiveInf(f32(-0.0))); - assert(!isPositiveInf(f64(0.0))); - assert(!isPositiveInf(f64(-0.0))); - assert(isPositiveInf(math.inf(f16))); - assert(!isPositiveInf(-math.inf(f16))); - assert(isPositiveInf(math.inf(f32))); - assert(!isPositiveInf(-math.inf(f32))); - assert(isPositiveInf(math.inf(f64))); - assert(!isPositiveInf(-math.inf(f64))); + expect(!isPositiveInf(f16(0.0))); + expect(!isPositiveInf(f16(-0.0))); + expect(!isPositiveInf(f32(0.0))); + expect(!isPositiveInf(f32(-0.0))); + expect(!isPositiveInf(f64(0.0))); + expect(!isPositiveInf(f64(-0.0))); + expect(isPositiveInf(math.inf(f16))); + expect(!isPositiveInf(-math.inf(f16))); + expect(isPositiveInf(math.inf(f32))); + expect(!isPositiveInf(-math.inf(f32))); + expect(isPositiveInf(math.inf(f64))); + expect(!isPositiveInf(-math.inf(f64))); } test "math.isNegativeInf" { - assert(!isNegativeInf(f16(0.0))); - assert(!isNegativeInf(f16(-0.0))); - assert(!isNegativeInf(f32(0.0))); - assert(!isNegativeInf(f32(-0.0))); - assert(!isNegativeInf(f64(0.0))); - assert(!isNegativeInf(f64(-0.0))); - assert(!isNegativeInf(math.inf(f16))); - assert(isNegativeInf(-math.inf(f16))); - assert(!isNegativeInf(math.inf(f32))); - assert(isNegativeInf(-math.inf(f32))); - assert(!isNegativeInf(math.inf(f64))); - assert(isNegativeInf(-math.inf(f64))); + expect(!isNegativeInf(f16(0.0))); + expect(!isNegativeInf(f16(-0.0))); + expect(!isNegativeInf(f32(0.0))); + expect(!isNegativeInf(f32(-0.0))); + expect(!isNegativeInf(f64(0.0))); + expect(!isNegativeInf(f64(-0.0))); + expect(!isNegativeInf(math.inf(f16))); + expect(isNegativeInf(-math.inf(f16))); + expect(!isNegativeInf(math.inf(f32))); + expect(isNegativeInf(-math.inf(f32))); + expect(!isNegativeInf(math.inf(f64))); + expect(isNegativeInf(-math.inf(f64))); } diff --git a/std/math/isnan.zig b/std/math/isnan.zig index a2cb85b4f7..641da9e620 100644 --- a/std/math/isnan.zig +++ b/std/math/isnan.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isNan(x: var) bool { @@ -31,10 +31,10 @@ pub fn isSignalNan(x: var) bool { } test "math.isNan" { - assert(isNan(math.nan(f16))); - assert(isNan(math.nan(f32))); - assert(isNan(math.nan(f64))); - assert(!isNan(f16(1.0))); - assert(!isNan(f32(1.0))); - assert(!isNan(f64(1.0))); + expect(isNan(math.nan(f16))); + expect(isNan(math.nan(f32))); + expect(isNan(math.nan(f64))); + expect(!isNan(f16(1.0))); + expect(!isNan(f32(1.0))); + expect(!isNan(f64(1.0))); } diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig index cc088e46a0..2c57aea7a9 100644 --- a/std/math/isnormal.zig +++ b/std/math/isnormal.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isNormal(x: var) bool { @@ -25,13 +25,13 @@ pub fn isNormal(x: var) bool { } test "math.isNormal" { - assert(!isNormal(math.nan(f16))); - assert(!isNormal(math.nan(f32))); - assert(!isNormal(math.nan(f64))); - assert(!isNormal(f16(0))); - assert(!isNormal(f32(0))); - assert(!isNormal(f64(0))); - assert(isNormal(f16(1.0))); - assert(isNormal(f32(1.0))); - assert(isNormal(f64(1.0))); + expect(!isNormal(math.nan(f16))); + expect(!isNormal(math.nan(f32))); + expect(!isNormal(math.nan(f64))); + expect(!isNormal(f16(0))); + expect(!isNormal(f32(0))); + expect(!isNormal(f64(0))); + expect(isNormal(f16(1.0))); + expect(isNormal(f32(1.0))); + expect(isNormal(f64(1.0))); } diff --git a/std/math/ln.zig b/std/math/ln.zig index a560fee8ec..257ce8054f 100644 --- a/std/math/ln.zig +++ b/std/math/ln.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; @@ -143,42 +143,42 @@ pub fn ln_64(x_: f64) f64 { } test "math.ln" { - assert(ln(f32(0.2)) == ln_32(0.2)); - assert(ln(f64(0.2)) == ln_64(0.2)); + expect(ln(f32(0.2)) == ln_32(0.2)); + expect(ln(f64(0.2)) == ln_64(0.2)); } test "math.ln32" { const epsilon = 0.000001; - assert(math.approxEq(f32, ln_32(0.2), -1.609438, epsilon)); - assert(math.approxEq(f32, ln_32(0.8923), -0.113953, epsilon)); - assert(math.approxEq(f32, ln_32(1.5), 0.405465, epsilon)); - assert(math.approxEq(f32, ln_32(37.45), 3.623007, epsilon)); - assert(math.approxEq(f32, ln_32(89.123), 4.490017, epsilon)); - assert(math.approxEq(f32, ln_32(123123.234375), 11.720941, epsilon)); + expect(math.approxEq(f32, ln_32(0.2), -1.609438, epsilon)); + expect(math.approxEq(f32, ln_32(0.8923), -0.113953, epsilon)); + expect(math.approxEq(f32, ln_32(1.5), 0.405465, epsilon)); + expect(math.approxEq(f32, ln_32(37.45), 3.623007, epsilon)); + expect(math.approxEq(f32, ln_32(89.123), 4.490017, epsilon)); + expect(math.approxEq(f32, ln_32(123123.234375), 11.720941, epsilon)); } test "math.ln64" { const epsilon = 0.000001; - assert(math.approxEq(f64, ln_64(0.2), -1.609438, epsilon)); - assert(math.approxEq(f64, ln_64(0.8923), -0.113953, epsilon)); - assert(math.approxEq(f64, ln_64(1.5), 0.405465, epsilon)); - assert(math.approxEq(f64, ln_64(37.45), 3.623007, epsilon)); - assert(math.approxEq(f64, ln_64(89.123), 4.490017, epsilon)); - assert(math.approxEq(f64, ln_64(123123.234375), 11.720941, epsilon)); + expect(math.approxEq(f64, ln_64(0.2), -1.609438, epsilon)); + expect(math.approxEq(f64, ln_64(0.8923), -0.113953, epsilon)); + expect(math.approxEq(f64, ln_64(1.5), 0.405465, epsilon)); + expect(math.approxEq(f64, ln_64(37.45), 3.623007, epsilon)); + expect(math.approxEq(f64, ln_64(89.123), 4.490017, epsilon)); + expect(math.approxEq(f64, ln_64(123123.234375), 11.720941, epsilon)); } test "math.ln32.special" { - assert(math.isPositiveInf(ln_32(math.inf(f32)))); - assert(math.isNegativeInf(ln_32(0.0))); - assert(math.isNan(ln_32(-1.0))); - assert(math.isNan(ln_32(math.nan(f32)))); + expect(math.isPositiveInf(ln_32(math.inf(f32)))); + expect(math.isNegativeInf(ln_32(0.0))); + expect(math.isNan(ln_32(-1.0))); + expect(math.isNan(ln_32(math.nan(f32)))); } test "math.ln64.special" { - assert(math.isPositiveInf(ln_64(math.inf(f64)))); - assert(math.isNegativeInf(ln_64(0.0))); - assert(math.isNan(ln_64(-1.0))); - assert(math.isNan(ln_64(math.nan(f64)))); + expect(math.isPositiveInf(ln_64(math.inf(f64)))); + expect(math.isNegativeInf(ln_64(0.0))); + expect(math.isNan(ln_64(-1.0))); + expect(math.isNan(ln_64(math.nan(f64)))); } diff --git a/std/math/log.zig b/std/math/log.zig index 20b6d055e8..21cffcc078 100644 --- a/std/math/log.zig +++ b/std/math/log.zig @@ -2,7 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const builtin = @import("builtin"); const TypeId = builtin.TypeId; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn log(comptime T: type, base: T, x: T) T { if (base == 2) { @@ -41,25 +41,25 @@ pub fn log(comptime T: type, base: T, x: T) T { } test "math.log integer" { - assert(log(u8, 2, 0x1) == 0); - assert(log(u8, 2, 0x2) == 1); - assert(log(i16, 2, 0x72) == 6); - assert(log(u32, 2, 0xFFFFFF) == 23); - assert(log(u64, 2, 0x7FF0123456789ABC) == 62); + expect(log(u8, 2, 0x1) == 0); + expect(log(u8, 2, 0x2) == 1); + expect(log(i16, 2, 0x72) == 6); + expect(log(u32, 2, 0xFFFFFF) == 23); + expect(log(u64, 2, 0x7FF0123456789ABC) == 62); } test "math.log float" { const epsilon = 0.000001; - assert(math.approxEq(f32, log(f32, 6, 0.23947), -0.797723, epsilon)); - assert(math.approxEq(f32, log(f32, 89, 0.23947), -0.318432, epsilon)); - assert(math.approxEq(f64, log(f64, 123897, 12389216414), 1.981724596, epsilon)); + expect(math.approxEq(f32, log(f32, 6, 0.23947), -0.797723, epsilon)); + expect(math.approxEq(f32, log(f32, 89, 0.23947), -0.318432, epsilon)); + expect(math.approxEq(f64, log(f64, 123897, 12389216414), 1.981724596, epsilon)); } test "math.log float_special" { - assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974))); - assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974))); + expect(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974))); + expect(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974))); - assert(log(f64, 2, 213.23019799993) == math.log2(f64(213.23019799993))); - assert(log(f64, 10, 213.23019799993) == math.log10(f64(213.23019799993))); + expect(log(f64, 2, 213.23019799993) == math.log2(f64(213.23019799993))); + expect(log(f64, 10, 213.23019799993) == math.log10(f64(213.23019799993))); } diff --git a/std/math/log10.zig b/std/math/log10.zig index 2b53d8a6ae..8055f71280 100644 --- a/std/math/log10.zig +++ b/std/math/log10.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -171,42 +171,42 @@ pub fn log10_64(x_: f64) f64 { } test "math.log10" { - assert(log10(f32(0.2)) == log10_32(0.2)); - assert(log10(f64(0.2)) == log10_64(0.2)); + testing.expect(log10(f32(0.2)) == log10_32(0.2)); + testing.expect(log10(f64(0.2)) == log10_64(0.2)); } test "math.log10_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon)); - assert(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon)); - assert(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon)); - assert(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon)); - assert(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon)); + testing.expect(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon)); + testing.expect(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon)); + testing.expect(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon)); + testing.expect(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon)); + testing.expect(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon)); + testing.expect(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon)); } test "math.log10_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon)); - assert(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon)); - assert(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon)); - assert(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon)); - assert(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon)); + testing.expect(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon)); + testing.expect(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon)); + testing.expect(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon)); + testing.expect(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon)); + testing.expect(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon)); + testing.expect(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon)); } test "math.log10_32.special" { - assert(math.isPositiveInf(log10_32(math.inf(f32)))); - assert(math.isNegativeInf(log10_32(0.0))); - assert(math.isNan(log10_32(-1.0))); - assert(math.isNan(log10_32(math.nan(f32)))); + testing.expect(math.isPositiveInf(log10_32(math.inf(f32)))); + testing.expect(math.isNegativeInf(log10_32(0.0))); + testing.expect(math.isNan(log10_32(-1.0))); + testing.expect(math.isNan(log10_32(math.nan(f32)))); } test "math.log10_64.special" { - assert(math.isPositiveInf(log10_64(math.inf(f64)))); - assert(math.isNegativeInf(log10_64(0.0))); - assert(math.isNan(log10_64(-1.0))); - assert(math.isNan(log10_64(math.nan(f64)))); + testing.expect(math.isPositiveInf(log10_64(math.inf(f64)))); + testing.expect(math.isNegativeInf(log10_64(0.0))); + testing.expect(math.isNan(log10_64(-1.0))); + testing.expect(math.isNan(log10_64(math.nan(f64)))); } diff --git a/std/math/log1p.zig b/std/math/log1p.zig index 903fceac05..257e7b90d4 100644 --- a/std/math/log1p.zig +++ b/std/math/log1p.zig @@ -9,7 +9,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn log1p(x: var) @typeOf(x) { const T = @typeOf(x); @@ -177,48 +177,48 @@ fn log1p_64(x: f64) f64 { } test "math.log1p" { - assert(log1p(f32(0.0)) == log1p_32(0.0)); - assert(log1p(f64(0.0)) == log1p_64(0.0)); + expect(log1p(f32(0.0)) == log1p_32(0.0)); + expect(log1p(f64(0.0)) == log1p_64(0.0)); } test "math.log1p_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon)); - assert(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon)); - assert(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon)); - assert(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon)); - assert(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon)); + expect(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon)); + expect(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon)); + expect(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon)); + expect(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon)); + expect(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon)); + expect(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon)); } test "math.log1p_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon)); - assert(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon)); - assert(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon)); - assert(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon)); - assert(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon)); + expect(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon)); + expect(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon)); + expect(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon)); + expect(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon)); + expect(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon)); + expect(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon)); } test "math.log1p_32.special" { - assert(math.isPositiveInf(log1p_32(math.inf(f32)))); - assert(log1p_32(0.0) == 0.0); - assert(log1p_32(-0.0) == -0.0); - assert(math.isNegativeInf(log1p_32(-1.0))); - assert(math.isNan(log1p_32(-2.0))); - assert(math.isNan(log1p_32(math.nan(f32)))); + expect(math.isPositiveInf(log1p_32(math.inf(f32)))); + expect(log1p_32(0.0) == 0.0); + expect(log1p_32(-0.0) == -0.0); + expect(math.isNegativeInf(log1p_32(-1.0))); + expect(math.isNan(log1p_32(-2.0))); + expect(math.isNan(log1p_32(math.nan(f32)))); } test "math.log1p_64.special" { - assert(math.isPositiveInf(log1p_64(math.inf(f64)))); - assert(log1p_64(0.0) == 0.0); - assert(log1p_64(-0.0) == -0.0); - assert(math.isNegativeInf(log1p_64(-1.0))); - assert(math.isNan(log1p_64(-2.0))); - assert(math.isNan(log1p_64(math.nan(f64)))); + expect(math.isPositiveInf(log1p_64(math.inf(f64)))); + expect(log1p_64(0.0) == 0.0); + expect(log1p_64(-0.0) == -0.0); + expect(math.isNegativeInf(log1p_64(-1.0))); + expect(math.isNan(log1p_64(-2.0))); + expect(math.isNan(log1p_64(math.nan(f64)))); } diff --git a/std/math/log2.zig b/std/math/log2.zig index 555c0bdf18..1bb51bf9f9 100644 --- a/std/math/log2.zig +++ b/std/math/log2.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -169,40 +169,40 @@ pub fn log2_64(x_: f64) f64 { } test "math.log2" { - assert(log2(f32(0.2)) == log2_32(0.2)); - assert(log2(f64(0.2)) == log2_64(0.2)); + expect(log2(f32(0.2)) == log2_32(0.2)); + expect(log2(f64(0.2)) == log2_64(0.2)); } test "math.log2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon)); - assert(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon)); - assert(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon)); - assert(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon)); + expect(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon)); + expect(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon)); + expect(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon)); + expect(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon)); + expect(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon)); } test "math.log2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon)); - assert(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon)); - assert(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon)); - assert(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon)); + expect(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon)); + expect(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon)); + expect(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon)); + expect(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon)); + expect(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon)); } test "math.log2_32.special" { - assert(math.isPositiveInf(log2_32(math.inf(f32)))); - assert(math.isNegativeInf(log2_32(0.0))); - assert(math.isNan(log2_32(-1.0))); - assert(math.isNan(log2_32(math.nan(f32)))); + expect(math.isPositiveInf(log2_32(math.inf(f32)))); + expect(math.isNegativeInf(log2_32(0.0))); + expect(math.isNan(log2_32(-1.0))); + expect(math.isNan(log2_32(math.nan(f32)))); } test "math.log2_64.special" { - assert(math.isPositiveInf(log2_64(math.inf(f64)))); - assert(math.isNegativeInf(log2_64(0.0))); - assert(math.isNan(log2_64(-1.0))); - assert(math.isNan(log2_64(math.nan(f64)))); + expect(math.isPositiveInf(log2_64(math.inf(f64)))); + expect(math.isNegativeInf(log2_64(0.0))); + expect(math.isNan(log2_64(-1.0))); + expect(math.isNan(log2_64(math.nan(f64)))); } diff --git a/std/math/modf.zig b/std/math/modf.zig index 0f619f25bc..2dadda76a9 100644 --- a/std/math/modf.zig +++ b/std/math/modf.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; fn modf_result(comptime T: type) type { @@ -119,11 +119,11 @@ test "math.modf" { const a = modf(f32(1.0)); const b = modf32(1.0); // NOTE: No struct comparison on generic return type function? non-named, makes sense, but still. - assert(a.ipart == b.ipart and a.fpart == b.fpart); + expect(a.ipart == b.ipart and a.fpart == b.fpart); const c = modf(f64(1.0)); const d = modf64(1.0); - assert(a.ipart == b.ipart and a.fpart == b.fpart); + expect(a.ipart == b.ipart and a.fpart == b.fpart); } test "math.modf32" { @@ -131,24 +131,24 @@ test "math.modf32" { var r: modf32_result = undefined; r = modf32(1.0); - assert(math.approxEq(f32, r.ipart, 1.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.0, epsilon)); + expect(math.approxEq(f32, r.ipart, 1.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.0, epsilon)); r = modf32(2.545); - assert(math.approxEq(f32, r.ipart, 2.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.545, epsilon)); + expect(math.approxEq(f32, r.ipart, 2.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.545, epsilon)); r = modf32(3.978123); - assert(math.approxEq(f32, r.ipart, 3.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.978123, epsilon)); + expect(math.approxEq(f32, r.ipart, 3.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.978123, epsilon)); r = modf32(43874.3); - assert(math.approxEq(f32, r.ipart, 43874, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.300781, epsilon)); + expect(math.approxEq(f32, r.ipart, 43874, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.300781, epsilon)); r = modf32(1234.340780); - assert(math.approxEq(f32, r.ipart, 1234, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.340820, epsilon)); + expect(math.approxEq(f32, r.ipart, 1234, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.340820, epsilon)); } test "math.modf64" { @@ -156,48 +156,48 @@ test "math.modf64" { var r: modf64_result = undefined; r = modf64(1.0); - assert(math.approxEq(f64, r.ipart, 1.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.0, epsilon)); + expect(math.approxEq(f64, r.ipart, 1.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.0, epsilon)); r = modf64(2.545); - assert(math.approxEq(f64, r.ipart, 2.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.545, epsilon)); + expect(math.approxEq(f64, r.ipart, 2.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.545, epsilon)); r = modf64(3.978123); - assert(math.approxEq(f64, r.ipart, 3.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.978123, epsilon)); + expect(math.approxEq(f64, r.ipart, 3.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.978123, epsilon)); r = modf64(43874.3); - assert(math.approxEq(f64, r.ipart, 43874, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.3, epsilon)); + expect(math.approxEq(f64, r.ipart, 43874, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.3, epsilon)); r = modf64(1234.340780); - assert(math.approxEq(f64, r.ipart, 1234, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.340780, epsilon)); + expect(math.approxEq(f64, r.ipart, 1234, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.340780, epsilon)); } test "math.modf32.special" { var r: modf32_result = undefined; r = modf32(math.inf(f32)); - assert(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); r = modf32(-math.inf(f32)); - assert(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); r = modf32(math.nan(f32)); - assert(math.isNan(r.ipart) and math.isNan(r.fpart)); + expect(math.isNan(r.ipart) and math.isNan(r.fpart)); } test "math.modf64.special" { var r: modf64_result = undefined; r = modf64(math.inf(f64)); - assert(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); r = modf64(-math.inf(f64)); - assert(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); r = modf64(math.nan(f64)); - assert(math.isNan(r.ipart) and math.isNan(r.fpart)); + expect(math.isNan(r.ipart) and math.isNan(r.fpart)); } diff --git a/std/math/pow.zig b/std/math/pow.zig index 39a2bfa9f7..f037f66d7e 100644 --- a/std/math/pow.zig +++ b/std/math/pow.zig @@ -24,7 +24,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; // This implementation is taken from the go stlib, musl is a bit more complex. pub fn pow(comptime T: type, x: T, y: T) T { @@ -179,56 +179,56 @@ fn isOddInteger(x: f64) bool { test "math.pow" { const epsilon = 0.000001; - assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon)); - assert(math.approxEq(f32, pow(f32, 0.8923, 3.3), 0.686572, epsilon)); - assert(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon)); - assert(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon)); - assert(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon)); - assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.8923, 3.3), 0.686572, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon)); + expect(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon)); + expect(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon)); + expect(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); - assert(math.approxEq(f64, pow(f64, 0.0, 3.3), 0.0, epsilon)); - assert(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon)); - assert(math.approxEq(f64, pow(f64, 0.2, 3.3), 0.004936, epsilon)); - assert(math.approxEq(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon)); - assert(math.approxEq(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon)); - assert(math.approxEq(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon)); + expect(math.approxEq(f64, pow(f64, 0.0, 3.3), 0.0, epsilon)); + expect(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon)); + expect(math.approxEq(f64, pow(f64, 0.2, 3.3), 0.004936, epsilon)); + expect(math.approxEq(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon)); + expect(math.approxEq(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon)); + expect(math.approxEq(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon)); } test "math.pow.special" { const epsilon = 0.000001; - assert(pow(f32, 4, 0.0) == 1.0); - assert(pow(f32, 7, -0.0) == 1.0); - assert(pow(f32, 45, 1.0) == 45); - assert(pow(f32, -45, 1.0) == -45); - assert(math.isNan(pow(f32, math.nan(f32), 5.0))); - assert(math.isNan(pow(f32, 5.0, math.nan(f32)))); - assert(math.isPositiveInf(pow(f32, 0.0, -1.0))); - //assert(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? - assert(math.isPositiveInf(pow(f32, 0.0, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -0.0, -math.inf(f32)))); - assert(pow(f32, 0.0, math.inf(f32)) == 0.0); - assert(pow(f32, -0.0, math.inf(f32)) == 0.0); - assert(math.isPositiveInf(pow(f32, 0.0, -2.0))); - assert(math.isPositiveInf(pow(f32, -0.0, -2.0))); - assert(pow(f32, 0.0, 1.0) == 0.0); - assert(pow(f32, -0.0, 1.0) == -0.0); - assert(pow(f32, 0.0, 2.0) == 0.0); - assert(pow(f32, -0.0, 2.0) == 0.0); - assert(math.approxEq(f32, pow(f32, -1.0, math.inf(f32)), 1.0, epsilon)); - assert(math.approxEq(f32, pow(f32, -1.0, -math.inf(f32)), 1.0, epsilon)); - assert(math.isPositiveInf(pow(f32, 1.2, math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -1.2, math.inf(f32)))); - assert(pow(f32, 1.2, -math.inf(f32)) == 0.0); - assert(pow(f32, -1.2, -math.inf(f32)) == 0.0); - assert(pow(f32, 0.2, math.inf(f32)) == 0.0); - assert(pow(f32, -0.2, math.inf(f32)) == 0.0); - assert(math.isPositiveInf(pow(f32, 0.2, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -0.2, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, math.inf(f32), 1.0))); - assert(pow(f32, math.inf(f32), -1.0) == 0.0); - //assert(pow(f32, -math.inf(f32), 5.0) == pow(f32, -0.0, -5.0)); TODO support negative 0? - assert(pow(f32, -math.inf(f32), -5.2) == pow(f32, -0.0, 5.2)); - assert(math.isNan(pow(f32, -1.0, 1.2))); - assert(math.isNan(pow(f32, -12.4, 78.5))); + expect(pow(f32, 4, 0.0) == 1.0); + expect(pow(f32, 7, -0.0) == 1.0); + expect(pow(f32, 45, 1.0) == 45); + expect(pow(f32, -45, 1.0) == -45); + expect(math.isNan(pow(f32, math.nan(f32), 5.0))); + expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); + expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); + //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? + expect(math.isPositiveInf(pow(f32, 0.0, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -0.0, -math.inf(f32)))); + expect(pow(f32, 0.0, math.inf(f32)) == 0.0); + expect(pow(f32, -0.0, math.inf(f32)) == 0.0); + expect(math.isPositiveInf(pow(f32, 0.0, -2.0))); + expect(math.isPositiveInf(pow(f32, -0.0, -2.0))); + expect(pow(f32, 0.0, 1.0) == 0.0); + expect(pow(f32, -0.0, 1.0) == -0.0); + expect(pow(f32, 0.0, 2.0) == 0.0); + expect(pow(f32, -0.0, 2.0) == 0.0); + expect(math.approxEq(f32, pow(f32, -1.0, math.inf(f32)), 1.0, epsilon)); + expect(math.approxEq(f32, pow(f32, -1.0, -math.inf(f32)), 1.0, epsilon)); + expect(math.isPositiveInf(pow(f32, 1.2, math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -1.2, math.inf(f32)))); + expect(pow(f32, 1.2, -math.inf(f32)) == 0.0); + expect(pow(f32, -1.2, -math.inf(f32)) == 0.0); + expect(pow(f32, 0.2, math.inf(f32)) == 0.0); + expect(pow(f32, -0.2, math.inf(f32)) == 0.0); + expect(math.isPositiveInf(pow(f32, 0.2, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -0.2, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, math.inf(f32), 1.0))); + expect(pow(f32, math.inf(f32), -1.0) == 0.0); + //expect(pow(f32, -math.inf(f32), 5.0) == pow(f32, -0.0, -5.0)); TODO support negative 0? + expect(pow(f32, -math.inf(f32), -5.2) == pow(f32, -0.0, 5.2)); + expect(math.isNan(pow(f32, -1.0, 1.2))); + expect(math.isNan(pow(f32, -12.4, 78.5))); } diff --git a/std/math/powi.zig b/std/math/powi.zig index 13c09b192e..9c2a4a4965 100644 --- a/std/math/powi.zig +++ b/std/math/powi.zig @@ -12,7 +12,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; const assert = std.debug.assert; -const assertError = std.debug.assertError; +const testing = std.testing; // This implementation is based on that from the rust stlib pub fn powi(comptime T: type, x: T, y: T) (error{ @@ -103,75 +103,75 @@ pub fn powi(comptime T: type, x: T, y: T) (error{ } test "math.powi" { - assertError(powi(i8, -66, 6), error.Underflow); - assertError(powi(i16, -13, 13), error.Underflow); - assertError(powi(i32, -32, 21), error.Underflow); - assertError(powi(i64, -24, 61), error.Underflow); - assertError(powi(i17, -15, 15), error.Underflow); - assertError(powi(i42, -6, 40), error.Underflow); + testing.expectError(error.Underflow, powi(i8, -66, 6)); + testing.expectError(error.Underflow, powi(i16, -13, 13)); + testing.expectError(error.Underflow, powi(i32, -32, 21)); + testing.expectError(error.Underflow, powi(i64, -24, 61)); + testing.expectError(error.Underflow, powi(i17, -15, 15)); + testing.expectError(error.Underflow, powi(i42, -6, 40)); - assert((try powi(i8, -5, 3)) == -125); - assert((try powi(i16, -16, 3)) == -4096); - assert((try powi(i32, -91, 3)) == -753571); - assert((try powi(i64, -36, 6)) == 2176782336); - assert((try powi(i17, -2, 15)) == -32768); - assert((try powi(i42, -5, 7)) == -78125); + testing.expect((try powi(i8, -5, 3)) == -125); + testing.expect((try powi(i16, -16, 3)) == -4096); + testing.expect((try powi(i32, -91, 3)) == -753571); + testing.expect((try powi(i64, -36, 6)) == 2176782336); + testing.expect((try powi(i17, -2, 15)) == -32768); + testing.expect((try powi(i42, -5, 7)) == -78125); - assert((try powi(u8, 6, 2)) == 36); - assert((try powi(u16, 5, 4)) == 625); - assert((try powi(u32, 12, 6)) == 2985984); - assert((try powi(u64, 34, 2)) == 1156); - assert((try powi(u17, 16, 3)) == 4096); - assert((try powi(u42, 34, 6)) == 1544804416); + testing.expect((try powi(u8, 6, 2)) == 36); + testing.expect((try powi(u16, 5, 4)) == 625); + testing.expect((try powi(u32, 12, 6)) == 2985984); + testing.expect((try powi(u64, 34, 2)) == 1156); + testing.expect((try powi(u17, 16, 3)) == 4096); + testing.expect((try powi(u42, 34, 6)) == 1544804416); - assertError(powi(i8, 120, 7), error.Overflow); - assertError(powi(i16, 73, 15), error.Overflow); - assertError(powi(i32, 23, 31), error.Overflow); - assertError(powi(i64, 68, 61), error.Overflow); - assertError(powi(i17, 15, 15), error.Overflow); - assertError(powi(i42, 121312, 41), error.Overflow); + testing.expectError(error.Overflow, powi(i8, 120, 7)); + testing.expectError(error.Overflow, powi(i16, 73, 15)); + testing.expectError(error.Overflow, powi(i32, 23, 31)); + testing.expectError(error.Overflow, powi(i64, 68, 61)); + testing.expectError(error.Overflow, powi(i17, 15, 15)); + testing.expectError(error.Overflow, powi(i42, 121312, 41)); - assertError(powi(u8, 123, 7), error.Overflow); - assertError(powi(u16, 2313, 15), error.Overflow); - assertError(powi(u32, 8968, 31), error.Overflow); - assertError(powi(u64, 2342, 63), error.Overflow); - assertError(powi(u17, 2723, 16), error.Overflow); - assertError(powi(u42, 8234, 41), error.Overflow); + testing.expectError(error.Overflow, powi(u8, 123, 7)); + testing.expectError(error.Overflow, powi(u16, 2313, 15)); + testing.expectError(error.Overflow, powi(u32, 8968, 31)); + testing.expectError(error.Overflow, powi(u64, 2342, 63)); + testing.expectError(error.Overflow, powi(u17, 2723, 16)); + testing.expectError(error.Overflow, powi(u42, 8234, 41)); } test "math.powi.special" { - assertError(powi(i8, -2, 8), error.Underflow); - assertError(powi(i16, -2, 16), error.Underflow); - assertError(powi(i32, -2, 32), error.Underflow); - assertError(powi(i64, -2, 64), error.Underflow); - assertError(powi(i17, -2, 17), error.Underflow); - assertError(powi(i42, -2, 42), error.Underflow); + testing.expectError(error.Underflow, powi(i8, -2, 8)); + testing.expectError(error.Underflow, powi(i16, -2, 16)); + testing.expectError(error.Underflow, powi(i32, -2, 32)); + testing.expectError(error.Underflow, powi(i64, -2, 64)); + testing.expectError(error.Underflow, powi(i17, -2, 17)); + testing.expectError(error.Underflow, powi(i42, -2, 42)); - assert((try powi(i8, -1, 3)) == -1); - assert((try powi(i16, -1, 2)) == 1); - assert((try powi(i32, -1, 16)) == 1); - assert((try powi(i64, -1, 6)) == 1); - assert((try powi(i17, -1, 15)) == -1); - assert((try powi(i42, -1, 7)) == -1); + testing.expect((try powi(i8, -1, 3)) == -1); + testing.expect((try powi(i16, -1, 2)) == 1); + testing.expect((try powi(i32, -1, 16)) == 1); + testing.expect((try powi(i64, -1, 6)) == 1); + testing.expect((try powi(i17, -1, 15)) == -1); + testing.expect((try powi(i42, -1, 7)) == -1); - assert((try powi(u8, 1, 2)) == 1); - assert((try powi(u16, 1, 4)) == 1); - assert((try powi(u32, 1, 6)) == 1); - assert((try powi(u64, 1, 2)) == 1); - assert((try powi(u17, 1, 3)) == 1); - assert((try powi(u42, 1, 6)) == 1); + testing.expect((try powi(u8, 1, 2)) == 1); + testing.expect((try powi(u16, 1, 4)) == 1); + testing.expect((try powi(u32, 1, 6)) == 1); + testing.expect((try powi(u64, 1, 2)) == 1); + testing.expect((try powi(u17, 1, 3)) == 1); + testing.expect((try powi(u42, 1, 6)) == 1); - assertError(powi(i8, 2, 7), error.Overflow); - assertError(powi(i16, 2, 15), error.Overflow); - assertError(powi(i32, 2, 31), error.Overflow); - assertError(powi(i64, 2, 63), error.Overflow); - assertError(powi(i17, 2, 16), error.Overflow); - assertError(powi(i42, 2, 41), error.Overflow); + testing.expectError(error.Overflow, powi(i8, 2, 7)); + testing.expectError(error.Overflow, powi(i16, 2, 15)); + testing.expectError(error.Overflow, powi(i32, 2, 31)); + testing.expectError(error.Overflow, powi(i64, 2, 63)); + testing.expectError(error.Overflow, powi(i17, 2, 16)); + testing.expectError(error.Overflow, powi(i42, 2, 41)); - assertError(powi(u8, 2, 8), error.Overflow); - assertError(powi(u16, 2, 16), error.Overflow); - assertError(powi(u32, 2, 32), error.Overflow); - assertError(powi(u64, 2, 64), error.Overflow); - assertError(powi(u17, 2, 17), error.Overflow); - assertError(powi(u42, 2, 42), error.Overflow); + testing.expectError(error.Overflow, powi(u8, 2, 8)); + testing.expectError(error.Overflow, powi(u16, 2, 16)); + testing.expectError(error.Overflow, powi(u32, 2, 32)); + testing.expectError(error.Overflow, powi(u64, 2, 64)); + testing.expectError(error.Overflow, powi(u17, 2, 17)); + testing.expectError(error.Overflow, powi(u42, 2, 42)); } diff --git a/std/math/round.zig b/std/math/round.zig index 4fe35365c8..7346b703c9 100644 --- a/std/math/round.zig +++ b/std/math/round.zig @@ -5,7 +5,7 @@ // - round(nan) = nan const builtin = @import("builtin"); -const assert = std.debug.assert; +const expect = std.testing.expect; const std = @import("../index.zig"); const math = std.math; @@ -85,36 +85,36 @@ fn round64(x_: f64) f64 { } test "math.round" { - assert(round(f32(1.3)) == round32(1.3)); - assert(round(f64(1.3)) == round64(1.3)); + expect(round(f32(1.3)) == round32(1.3)); + expect(round(f64(1.3)) == round64(1.3)); } test "math.round32" { - assert(round32(1.3) == 1.0); - assert(round32(-1.3) == -1.0); - assert(round32(0.2) == 0.0); - assert(round32(1.8) == 2.0); + expect(round32(1.3) == 1.0); + expect(round32(-1.3) == -1.0); + expect(round32(0.2) == 0.0); + expect(round32(1.8) == 2.0); } test "math.round64" { - assert(round64(1.3) == 1.0); - assert(round64(-1.3) == -1.0); - assert(round64(0.2) == 0.0); - assert(round64(1.8) == 2.0); + expect(round64(1.3) == 1.0); + expect(round64(-1.3) == -1.0); + expect(round64(0.2) == 0.0); + expect(round64(1.8) == 2.0); } test "math.round32.special" { - assert(round32(0.0) == 0.0); - assert(round32(-0.0) == -0.0); - assert(math.isPositiveInf(round32(math.inf(f32)))); - assert(math.isNegativeInf(round32(-math.inf(f32)))); - assert(math.isNan(round32(math.nan(f32)))); + expect(round32(0.0) == 0.0); + expect(round32(-0.0) == -0.0); + expect(math.isPositiveInf(round32(math.inf(f32)))); + expect(math.isNegativeInf(round32(-math.inf(f32)))); + expect(math.isNan(round32(math.nan(f32)))); } test "math.round64.special" { - assert(round64(0.0) == 0.0); - assert(round64(-0.0) == -0.0); - assert(math.isPositiveInf(round64(math.inf(f64)))); - assert(math.isNegativeInf(round64(-math.inf(f64)))); - assert(math.isNan(round64(math.nan(f64)))); + expect(round64(0.0) == 0.0); + expect(round64(-0.0) == -0.0); + expect(math.isPositiveInf(round64(math.inf(f64)))); + expect(math.isNegativeInf(round64(-math.inf(f64)))); + expect(math.isNan(round64(math.nan(f64)))); } diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig index f72c7e866f..d37a8659a9 100644 --- a/std/math/scalbn.zig +++ b/std/math/scalbn.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn scalbn(x: var, n: i32) @typeOf(x) { const T = @typeOf(x); @@ -72,14 +72,14 @@ fn scalbn64(x: f64, n_: i32) f64 { } test "math.scalbn" { - assert(scalbn(f32(1.5), 4) == scalbn32(1.5, 4)); - assert(scalbn(f64(1.5), 4) == scalbn64(1.5, 4)); + expect(scalbn(f32(1.5), 4) == scalbn32(1.5, 4)); + expect(scalbn(f64(1.5), 4) == scalbn64(1.5, 4)); } test "math.scalbn32" { - assert(scalbn32(1.5, 4) == 24.0); + expect(scalbn32(1.5, 4) == 24.0); } test "math.scalbn64" { - assert(scalbn64(1.5, 4) == 24.0); + expect(scalbn64(1.5, 4) == 24.0); } diff --git a/std/math/signbit.zig b/std/math/signbit.zig index 8c6829dfcd..728f651aec 100644 --- a/std/math/signbit.zig +++ b/std/math/signbit.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn signbit(x: var) bool { const T = @typeOf(x); @@ -28,22 +28,22 @@ fn signbit64(x: f64) bool { } test "math.signbit" { - assert(signbit(f16(4.0)) == signbit16(4.0)); - assert(signbit(f32(4.0)) == signbit32(4.0)); - assert(signbit(f64(4.0)) == signbit64(4.0)); + expect(signbit(f16(4.0)) == signbit16(4.0)); + expect(signbit(f32(4.0)) == signbit32(4.0)); + expect(signbit(f64(4.0)) == signbit64(4.0)); } test "math.signbit16" { - assert(!signbit16(4.0)); - assert(signbit16(-3.0)); + expect(!signbit16(4.0)); + expect(signbit16(-3.0)); } test "math.signbit32" { - assert(!signbit32(4.0)); - assert(signbit32(-3.0)); + expect(!signbit32(4.0)); + expect(signbit32(-3.0)); } test "math.signbit64" { - assert(!signbit64(4.0)); - assert(signbit64(-3.0)); + expect(!signbit64(4.0)); + expect(signbit64(-3.0)); } diff --git a/std/math/sin.zig b/std/math/sin.zig index 15b2f9f17a..5ade6636c7 100644 --- a/std/math/sin.zig +++ b/std/math/sin.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn sin(x: var) @typeOf(x) { const T = @typeOf(x); @@ -142,45 +142,45 @@ fn sin64(x_: f64) f64 { } test "math.sin" { - assert(sin(f32(0.0)) == sin32(0.0)); - assert(sin(f64(0.0)) == sin64(0.0)); - assert(comptime (math.sin(f64(2))) == math.sin(f64(2))); + expect(sin(f32(0.0)) == sin32(0.0)); + expect(sin(f64(0.0)) == sin64(0.0)); + expect(comptime (math.sin(f64(2))) == math.sin(f64(2))); } test "math.sin32" { const epsilon = 0.000001; - assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); - assert(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); - assert(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); - assert(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); - assert(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); + expect(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); + expect(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); + expect(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); + expect(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); + expect(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); } test "math.sin64" { const epsilon = 0.000001; - assert(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); - assert(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); - assert(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); - assert(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); - assert(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); + expect(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); + expect(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); + expect(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); + expect(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); + expect(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); } test "math.sin32.special" { - assert(sin32(0.0) == 0.0); - assert(sin32(-0.0) == -0.0); - assert(math.isNan(sin32(math.inf(f32)))); - assert(math.isNan(sin32(-math.inf(f32)))); - assert(math.isNan(sin32(math.nan(f32)))); + expect(sin32(0.0) == 0.0); + expect(sin32(-0.0) == -0.0); + expect(math.isNan(sin32(math.inf(f32)))); + expect(math.isNan(sin32(-math.inf(f32)))); + expect(math.isNan(sin32(math.nan(f32)))); } test "math.sin64.special" { - assert(sin64(0.0) == 0.0); - assert(sin64(-0.0) == -0.0); - assert(math.isNan(sin64(math.inf(f64)))); - assert(math.isNan(sin64(-math.inf(f64)))); - assert(math.isNan(sin64(math.nan(f64)))); + expect(sin64(0.0) == 0.0); + expect(sin64(-0.0) == -0.0); + expect(math.isNan(sin64(math.inf(f64)))); + expect(math.isNan(sin64(-math.inf(f64)))); + expect(math.isNan(sin64(math.nan(f64)))); } diff --git a/std/math/sinh.zig b/std/math/sinh.zig index 733b89754a..95924ba55a 100644 --- a/std/math/sinh.zig +++ b/std/math/sinh.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; @@ -87,40 +87,40 @@ fn sinh64(x: f64) f64 { } test "math.sinh" { - assert(sinh(f32(1.5)) == sinh32(1.5)); - assert(sinh(f64(1.5)) == sinh64(1.5)); + expect(sinh(f32(1.5)) == sinh32(1.5)); + expect(sinh(f64(1.5)) == sinh64(1.5)); } test "math.sinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, sinh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon)); - assert(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon)); + expect(math.approxEq(f32, sinh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon)); + expect(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon)); + expect(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon)); } test "math.sinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, sinh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon)); - assert(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon)); + expect(math.approxEq(f64, sinh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon)); + expect(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon)); + expect(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon)); } test "math.sinh32.special" { - assert(sinh32(0.0) == 0.0); - assert(sinh32(-0.0) == -0.0); - assert(math.isPositiveInf(sinh32(math.inf(f32)))); - assert(math.isNegativeInf(sinh32(-math.inf(f32)))); - assert(math.isNan(sinh32(math.nan(f32)))); + expect(sinh32(0.0) == 0.0); + expect(sinh32(-0.0) == -0.0); + expect(math.isPositiveInf(sinh32(math.inf(f32)))); + expect(math.isNegativeInf(sinh32(-math.inf(f32)))); + expect(math.isNan(sinh32(math.nan(f32)))); } test "math.sinh64.special" { - assert(sinh64(0.0) == 0.0); - assert(sinh64(-0.0) == -0.0); - assert(math.isPositiveInf(sinh64(math.inf(f64)))); - assert(math.isNegativeInf(sinh64(-math.inf(f64)))); - assert(math.isNan(sinh64(math.nan(f64)))); + expect(sinh64(0.0) == 0.0); + expect(sinh64(-0.0) == -0.0); + expect(math.isPositiveInf(sinh64(math.inf(f64)))); + expect(math.isNegativeInf(sinh64(-math.inf(f64)))); + expect(math.isNan(sinh64(math.nan(f64)))); } diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig index 4300f20f5a..9996b44b20 100644 --- a/std/math/sqrt.zig +++ b/std/math/sqrt.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -32,75 +32,75 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ } test "math.sqrt" { - assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0)); - assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); - assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); + expect(sqrt(f16(0.0)) == @sqrt(f16, 0.0)); + expect(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); + expect(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); } test "math.sqrt16" { const epsilon = 0.000001; - assert(@sqrt(f16, 0.0) == 0.0); - assert(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon)); - assert(@sqrt(f16, 4.0) == 2.0); - assert(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f16, 64.0) == 8.0); - assert(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon)); + expect(@sqrt(f16, 0.0) == 0.0); + expect(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon)); + expect(@sqrt(f16, 4.0) == 2.0); + expect(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f16, 64.0) == 8.0); + expect(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon)); } test "math.sqrt32" { const epsilon = 0.000001; - assert(@sqrt(f32, 0.0) == 0.0); - assert(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon)); - assert(@sqrt(f32, 4.0) == 2.0); - assert(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f32, 64.0) == 8.0); - assert(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon)); + expect(@sqrt(f32, 0.0) == 0.0); + expect(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon)); + expect(@sqrt(f32, 4.0) == 2.0); + expect(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f32, 64.0) == 8.0); + expect(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon)); } test "math.sqrt64" { const epsilon = 0.000001; - assert(@sqrt(f64, 0.0) == 0.0); - assert(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon)); - assert(@sqrt(f64, 4.0) == 2.0); - assert(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f64, 64.0) == 8.0); - assert(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); + expect(@sqrt(f64, 0.0) == 0.0); + expect(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon)); + expect(@sqrt(f64, 4.0) == 2.0); + expect(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f64, 64.0) == 8.0); + expect(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); } test "math.sqrt16.special" { - assert(math.isPositiveInf(@sqrt(f16, math.inf(f16)))); - assert(@sqrt(f16, 0.0) == 0.0); - assert(@sqrt(f16, -0.0) == -0.0); - assert(math.isNan(@sqrt(f16, -1.0))); - assert(math.isNan(@sqrt(f16, math.nan(f16)))); + expect(math.isPositiveInf(@sqrt(f16, math.inf(f16)))); + expect(@sqrt(f16, 0.0) == 0.0); + expect(@sqrt(f16, -0.0) == -0.0); + expect(math.isNan(@sqrt(f16, -1.0))); + expect(math.isNan(@sqrt(f16, math.nan(f16)))); } test "math.sqrt32.special" { - assert(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); - assert(@sqrt(f32, 0.0) == 0.0); - assert(@sqrt(f32, -0.0) == -0.0); - assert(math.isNan(@sqrt(f32, -1.0))); - assert(math.isNan(@sqrt(f32, math.nan(f32)))); + expect(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); + expect(@sqrt(f32, 0.0) == 0.0); + expect(@sqrt(f32, -0.0) == -0.0); + expect(math.isNan(@sqrt(f32, -1.0))); + expect(math.isNan(@sqrt(f32, math.nan(f32)))); } test "math.sqrt64.special" { - assert(math.isPositiveInf(@sqrt(f64, math.inf(f64)))); - assert(@sqrt(f64, 0.0) == 0.0); - assert(@sqrt(f64, -0.0) == -0.0); - assert(math.isNan(@sqrt(f64, -1.0))); - assert(math.isNan(@sqrt(f64, math.nan(f64)))); + expect(math.isPositiveInf(@sqrt(f64, math.inf(f64)))); + expect(@sqrt(f64, 0.0) == 0.0); + expect(@sqrt(f64, -0.0) == -0.0); + expect(math.isNan(@sqrt(f64, -1.0))); + expect(math.isNan(@sqrt(f64, math.nan(f64)))); } fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { @@ -127,10 +127,10 @@ fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { } test "math.sqrt_int" { - assert(sqrt_int(u32, 3) == 1); - assert(sqrt_int(u32, 4) == 2); - assert(sqrt_int(u32, 5) == 2); - assert(sqrt_int(u32, 8) == 2); - assert(sqrt_int(u32, 9) == 3); - assert(sqrt_int(u32, 10) == 3); + expect(sqrt_int(u32, 3) == 1); + expect(sqrt_int(u32, 4) == 2); + expect(sqrt_int(u32, 5) == 2); + expect(sqrt_int(u32, 8) == 2); + expect(sqrt_int(u32, 9) == 3); + expect(sqrt_int(u32, 10) == 3); } diff --git a/std/math/tan.zig b/std/math/tan.zig index a71a17e625..ec43092320 100644 --- a/std/math/tan.zig +++ b/std/math/tan.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn tan(x: var) @typeOf(x) { const T = @typeOf(x); @@ -129,44 +129,44 @@ fn tan64(x_: f64) f64 { } test "math.tan" { - assert(tan(f32(0.0)) == tan32(0.0)); - assert(tan(f64(0.0)) == tan64(0.0)); + expect(tan(f32(0.0)) == tan32(0.0)); + expect(tan(f64(0.0)) == tan64(0.0)); } test "math.tan32" { const epsilon = 0.000001; - assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); - assert(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); - assert(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); - assert(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); - assert(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); + expect(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); + expect(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); + expect(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); + expect(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); + expect(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); } test "math.tan64" { const epsilon = 0.000001; - assert(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); - assert(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); - assert(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); - assert(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); - assert(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); + expect(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); + expect(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); + expect(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); + expect(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); + expect(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); } test "math.tan32.special" { - assert(tan32(0.0) == 0.0); - assert(tan32(-0.0) == -0.0); - assert(math.isNan(tan32(math.inf(f32)))); - assert(math.isNan(tan32(-math.inf(f32)))); - assert(math.isNan(tan32(math.nan(f32)))); + expect(tan32(0.0) == 0.0); + expect(tan32(-0.0) == -0.0); + expect(math.isNan(tan32(math.inf(f32)))); + expect(math.isNan(tan32(-math.inf(f32)))); + expect(math.isNan(tan32(math.nan(f32)))); } test "math.tan64.special" { - assert(tan64(0.0) == 0.0); - assert(tan64(-0.0) == -0.0); - assert(math.isNan(tan64(math.inf(f64)))); - assert(math.isNan(tan64(-math.inf(f64)))); - assert(math.isNan(tan64(math.nan(f64)))); + expect(tan64(0.0) == 0.0); + expect(tan64(-0.0) == -0.0); + expect(math.isNan(tan64(math.inf(f64)))); + expect(math.isNan(tan64(-math.inf(f64)))); + expect(math.isNan(tan64(math.nan(f64)))); } diff --git a/std/math/tanh.zig b/std/math/tanh.zig index faeb2641cc..a35449a053 100644 --- a/std/math/tanh.zig +++ b/std/math/tanh.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; @@ -113,42 +113,42 @@ fn tanh64(x: f64) f64 { } test "math.tanh" { - assert(tanh(f32(1.5)) == tanh32(1.5)); - assert(tanh(f64(1.5)) == tanh64(1.5)); + expect(tanh(f32(1.5)) == tanh32(1.5)); + expect(tanh(f64(1.5)) == tanh64(1.5)); } test "math.tanh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, tanh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon)); - assert(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon)); - assert(math.approxEq(f32, tanh32(37.45), 1.0, epsilon)); + expect(math.approxEq(f32, tanh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon)); + expect(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon)); + expect(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon)); + expect(math.approxEq(f32, tanh32(37.45), 1.0, epsilon)); } test "math.tanh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, tanh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon)); - assert(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon)); - assert(math.approxEq(f64, tanh64(37.45), 1.0, epsilon)); + expect(math.approxEq(f64, tanh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon)); + expect(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon)); + expect(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon)); + expect(math.approxEq(f64, tanh64(37.45), 1.0, epsilon)); } test "math.tanh32.special" { - assert(tanh32(0.0) == 0.0); - assert(tanh32(-0.0) == -0.0); - assert(tanh32(math.inf(f32)) == 1.0); - assert(tanh32(-math.inf(f32)) == -1.0); - assert(math.isNan(tanh32(math.nan(f32)))); + expect(tanh32(0.0) == 0.0); + expect(tanh32(-0.0) == -0.0); + expect(tanh32(math.inf(f32)) == 1.0); + expect(tanh32(-math.inf(f32)) == -1.0); + expect(math.isNan(tanh32(math.nan(f32)))); } test "math.tanh64.special" { - assert(tanh64(0.0) == 0.0); - assert(tanh64(-0.0) == -0.0); - assert(tanh64(math.inf(f64)) == 1.0); - assert(tanh64(-math.inf(f64)) == -1.0); - assert(math.isNan(tanh64(math.nan(f64)))); + expect(tanh64(0.0) == 0.0); + expect(tanh64(-0.0) == -0.0); + expect(tanh64(math.inf(f64)) == 1.0); + expect(tanh64(-math.inf(f64)) == -1.0); + expect(math.isNan(tanh64(math.nan(f64)))); } diff --git a/std/math/trunc.zig b/std/math/trunc.zig index bb309a1e24..8c91ccc568 100644 --- a/std/math/trunc.zig +++ b/std/math/trunc.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn trunc(x: var) @typeOf(x) { @@ -61,34 +61,34 @@ fn trunc64(x: f64) f64 { } test "math.trunc" { - assert(trunc(f32(1.3)) == trunc32(1.3)); - assert(trunc(f64(1.3)) == trunc64(1.3)); + expect(trunc(f32(1.3)) == trunc32(1.3)); + expect(trunc(f64(1.3)) == trunc64(1.3)); } test "math.trunc32" { - assert(trunc32(1.3) == 1.0); - assert(trunc32(-1.3) == -1.0); - assert(trunc32(0.2) == 0.0); + expect(trunc32(1.3) == 1.0); + expect(trunc32(-1.3) == -1.0); + expect(trunc32(0.2) == 0.0); } test "math.trunc64" { - assert(trunc64(1.3) == 1.0); - assert(trunc64(-1.3) == -1.0); - assert(trunc64(0.2) == 0.0); + expect(trunc64(1.3) == 1.0); + expect(trunc64(-1.3) == -1.0); + expect(trunc64(0.2) == 0.0); } test "math.trunc32.special" { - assert(trunc32(0.0) == 0.0); // 0x3F800000 - assert(trunc32(-0.0) == -0.0); - assert(math.isPositiveInf(trunc32(math.inf(f32)))); - assert(math.isNegativeInf(trunc32(-math.inf(f32)))); - assert(math.isNan(trunc32(math.nan(f32)))); + expect(trunc32(0.0) == 0.0); // 0x3F800000 + expect(trunc32(-0.0) == -0.0); + expect(math.isPositiveInf(trunc32(math.inf(f32)))); + expect(math.isNegativeInf(trunc32(-math.inf(f32)))); + expect(math.isNan(trunc32(math.nan(f32)))); } test "math.trunc64.special" { - assert(trunc64(0.0) == 0.0); - assert(trunc64(-0.0) == -0.0); - assert(math.isPositiveInf(trunc64(math.inf(f64)))); - assert(math.isNegativeInf(trunc64(-math.inf(f64)))); - assert(math.isNan(trunc64(math.nan(f64)))); + expect(trunc64(0.0) == 0.0); + expect(trunc64(-0.0) == -0.0); + expect(math.isPositiveInf(trunc64(math.inf(f64)))); + expect(math.isNegativeInf(trunc64(-math.inf(f64)))); + expect(math.isNan(trunc64(math.nan(f64)))); } diff --git a/std/mem.zig b/std/mem.zig index a6cbae744f..1c7523bf13 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -6,6 +6,7 @@ const builtin = @import("builtin"); const mem = @This(); const meta = std.meta; const trait = meta.trait; +const testing = std.testing; pub const Allocator = struct { pub const Error = error{OutOfMemory}; @@ -181,7 +182,7 @@ test "mem.secureZero" { set(u8, a[0..], 0); secureZero(u8, b[0..]); - assert(eql(u8, a[0..], b[0..])); + testing.expectEqualSlices(u8, a[0..], b[0..]); } pub fn compare(comptime T: type, lhs: []const T, rhs: []const T) Compare { @@ -210,11 +211,11 @@ pub fn compare(comptime T: type, lhs: []const T, rhs: []const T) Compare { } test "mem.compare" { - assert(compare(u8, "abcd", "bee") == Compare.LessThan); - assert(compare(u8, "abc", "abc") == Compare.Equal); - assert(compare(u8, "abc", "abc0") == Compare.LessThan); - assert(compare(u8, "", "") == Compare.Equal); - assert(compare(u8, "", "a") == Compare.LessThan); + testing.expect(compare(u8, "abcd", "bee") == Compare.LessThan); + testing.expect(compare(u8, "abc", "abc") == Compare.Equal); + testing.expect(compare(u8, "abc", "abc0") == Compare.LessThan); + testing.expect(compare(u8, "", "") == Compare.Equal); + testing.expect(compare(u8, "", "a") == Compare.LessThan); } /// Returns true if lhs < rhs, false otherwise @@ -227,11 +228,11 @@ pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) bool { } test "mem.lessThan" { - assert(lessThan(u8, "abcd", "bee")); - assert(!lessThan(u8, "abc", "abc")); - assert(lessThan(u8, "abc", "abc0")); - assert(!lessThan(u8, "", "")); - assert(lessThan(u8, "", "a")); + testing.expect(lessThan(u8, "abcd", "bee")); + testing.expect(!lessThan(u8, "abc", "abc")); + testing.expect(lessThan(u8, "abc", "abc0")); + testing.expect(!lessThan(u8, "", "")); + testing.expect(lessThan(u8, "", "a")); } /// Compares two slices and returns whether they are equal. @@ -296,10 +297,10 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co } test "mem.trim" { - assert(eql(u8, trimLeft(u8, " foo\n ", " \n"), "foo\n ")); - assert(eql(u8, trimRight(u8, " foo\n ", " \n"), " foo")); - assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo")); - assert(eql(u8, trim(u8, "foo", " \n"), "foo")); + testing.expectEqualSlices(u8, "foo\n ", trimLeft(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, " foo", trimRight(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, "foo", trim(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n")); } /// Linear search for the index of a scalar value inside a slice. @@ -380,20 +381,20 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee } test "mem.indexOf" { - assert(indexOf(u8, "one two three four", "four").? == 14); - assert(lastIndexOf(u8, "one two three two four", "two").? == 14); - assert(indexOf(u8, "one two three four", "gour") == null); - assert(lastIndexOf(u8, "one two three four", "gour") == null); - assert(indexOf(u8, "foo", "foo").? == 0); - assert(lastIndexOf(u8, "foo", "foo").? == 0); - assert(indexOf(u8, "foo", "fool") == null); - assert(lastIndexOf(u8, "foo", "lfoo") == null); - assert(lastIndexOf(u8, "foo", "fool") == null); + testing.expect(indexOf(u8, "one two three four", "four").? == 14); + testing.expect(lastIndexOf(u8, "one two three two four", "two").? == 14); + testing.expect(indexOf(u8, "one two three four", "gour") == null); + testing.expect(lastIndexOf(u8, "one two three four", "gour") == null); + testing.expect(indexOf(u8, "foo", "foo").? == 0); + testing.expect(lastIndexOf(u8, "foo", "foo").? == 0); + testing.expect(indexOf(u8, "foo", "fool") == null); + testing.expect(lastIndexOf(u8, "foo", "lfoo") == null); + testing.expect(lastIndexOf(u8, "foo", "fool") == null); - assert(indexOf(u8, "foo foo", "foo").? == 0); - assert(lastIndexOf(u8, "foo foo", "foo").? == 4); - assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); - assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); + testing.expect(indexOf(u8, "foo foo", "foo").? == 0); + testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4); + testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); + testing.expect(lastIndexOfScalar(u8, "boo", 'o').? == 2); } /// Reads an integer from memory with size equal to bytes.len. @@ -504,34 +505,34 @@ test "comptime read/write int" { var bytes: [2]u8 = undefined; std.mem.writeIntLittle(u16, &bytes, 0x1234); const result = std.mem.readIntBig(u16, &bytes); - std.debug.assert(result == 0x3412); + testing.expect(result == 0x3412); } comptime { var bytes: [2]u8 = undefined; std.mem.writeIntBig(u16, &bytes, 0x1234); const result = std.mem.readIntLittle(u16, &bytes); - std.debug.assert(result == 0x3412); + testing.expect(result == 0x3412); } } test "readIntBig and readIntLittle" { - assert(readIntSliceBig(u0, []u8{}) == 0x0); - assert(readIntSliceLittle(u0, []u8{}) == 0x0); + testing.expect(readIntSliceBig(u0, []u8{}) == 0x0); + testing.expect(readIntSliceLittle(u0, []u8{}) == 0x0); - assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); - assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); + testing.expect(readIntSliceBig(u8, []u8{0x32}) == 0x32); + testing.expect(readIntSliceLittle(u8, []u8{0x12}) == 0x12); - assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); - assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); + testing.expect(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + testing.expect(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); - assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + testing.expect(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + testing.expect(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - assert(readIntSliceBig(i8, []u8{0xff}) == -1); - assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); + testing.expect(readIntSliceBig(i8, []u8{0xff}) == -1); + testing.expect(readIntSliceLittle(i8, []u8{0xfe}) == -2); - assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); - assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); + testing.expect(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + testing.expect(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); } /// Writes an integer to memory, storing it in twos-complement. @@ -645,34 +646,34 @@ test "writeIntBig and writeIntLittle" { var buf9: [9]u8 = undefined; writeIntBig(u0, &buf0, 0x0); - assert(eql_slice_u8(buf0[0..], []u8{})); + testing.expect(eql_slice_u8(buf0[0..], []u8{})); writeIntLittle(u0, &buf0, 0x0); - assert(eql_slice_u8(buf0[0..], []u8{})); + testing.expect(eql_slice_u8(buf0[0..], []u8{})); writeIntBig(u8, &buf1, 0x12); - assert(eql_slice_u8(buf1[0..], []u8{0x12})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0x12})); writeIntLittle(u8, &buf1, 0x34); - assert(eql_slice_u8(buf1[0..], []u8{0x34})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0x34})); writeIntBig(u16, &buf2, 0x1234); - assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); writeIntLittle(u16, &buf2, 0x5678); - assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); writeIntBig(u72, &buf9, 0x123456789abcdef024); - assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); + testing.expect(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); - assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); + testing.expect(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); writeIntBig(i8, &buf1, -1); - assert(eql_slice_u8(buf1[0..], []u8{0xff})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0xff})); writeIntLittle(i8, &buf1, -2); - assert(eql_slice_u8(buf1[0..], []u8{0xfe})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0xfe})); writeIntBig(i16, &buf2, -3); - assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); writeIntLittle(i16, &buf2, -4); - assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } pub fn hash_slice_u8(k: []const u8) u32 { @@ -706,46 +707,46 @@ pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator { test "mem.tokenize" { var it = tokenize(" abc def ghi ", " "); - assert(eql(u8, it.next().?, "abc")); - assert(eql(u8, it.next().?, "def")); - assert(eql(u8, it.next().?, "ghi")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "abc")); + testing.expect(eql(u8, it.next().?, "def")); + testing.expect(eql(u8, it.next().?, "ghi")); + testing.expect(it.next() == null); it = tokenize("..\\bob", "\\"); - assert(eql(u8, it.next().?, "..")); - assert(eql(u8, "..", "..\\bob"[0..it.index])); - assert(eql(u8, it.next().?, "bob")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "..")); + testing.expect(eql(u8, "..", "..\\bob"[0..it.index])); + testing.expect(eql(u8, it.next().?, "bob")); + testing.expect(it.next() == null); it = tokenize("//a/b", "/"); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b")); - assert(eql(u8, "//a/b", "//a/b"[0..it.index])); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b")); + testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index])); + testing.expect(it.next() == null); it = tokenize("|", "|"); - assert(it.next() == null); + testing.expect(it.next() == null); it = tokenize("", "|"); - assert(it.next() == null); + testing.expect(it.next() == null); it = tokenize("hello", ""); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); it = tokenize("hello", " "); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); } test "mem.tokenize (multibyte)" { var it = tokenize("a|b,c/d e", " /,|"); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b")); - assert(eql(u8, it.next().?, "c")); - assert(eql(u8, it.next().?, "d")); - assert(eql(u8, it.next().?, "e")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b")); + testing.expect(eql(u8, it.next().?, "c")); + testing.expect(eql(u8, it.next().?, "d")); + testing.expect(eql(u8, it.next().?, "e")); + testing.expect(it.next() == null); } /// Returns an iterator that iterates over the slices of `buffer` that @@ -769,34 +770,34 @@ pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { test "mem.separate" { var it = separate("abc|def||ghi", "|"); - assert(eql(u8, it.next().?, "abc")); - assert(eql(u8, it.next().?, "def")); - assert(eql(u8, it.next().?, "")); - assert(eql(u8, it.next().?, "ghi")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "abc")); + testing.expect(eql(u8, it.next().?, "def")); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(eql(u8, it.next().?, "ghi")); + testing.expect(it.next() == null); it = separate("", "|"); - assert(eql(u8, it.next().?, "")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(it.next() == null); it = separate("|", "|"); - assert(eql(u8, it.next().?, "")); - assert(eql(u8, it.next().?, "")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(it.next() == null); it = separate("hello", " "); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); } test "mem.separate (multibyte)" { var it = separate("a, b ,, c, d, e", ", "); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b ,")); - assert(eql(u8, it.next().?, "c")); - assert(eql(u8, it.next().?, "d")); - assert(eql(u8, it.next().?, "e")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b ,")); + testing.expect(eql(u8, it.next().?, "c")); + testing.expect(eql(u8, it.next().?, "d")); + testing.expect(eql(u8, it.next().?, "e")); + testing.expect(it.next() == null); } pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { @@ -804,8 +805,8 @@ pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool } test "mem.startsWith" { - assert(startsWith(u8, "Bob", "Bo")); - assert(!startsWith(u8, "Needle in haystack", "haystack")); + testing.expect(startsWith(u8, "Bob", "Bo")); + testing.expect(!startsWith(u8, "Needle in haystack", "haystack")); } pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool { @@ -813,8 +814,8 @@ pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool { } test "mem.endsWith" { - assert(endsWith(u8, "Needle in haystack", "haystack")); - assert(!endsWith(u8, "Bob", "Bo")); + testing.expect(endsWith(u8, "Needle in haystack", "haystack")); + testing.expect(!endsWith(u8, "Bob", "Bo")); } pub const TokenIterator = struct { @@ -913,15 +914,15 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons test "mem.join" { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; - assert(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); - assert(eql(u8, try join(a, ",", [][]const u8{"a"}), "a")); - assert(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{"a"}), "a")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); } test "testStringEquality" { - assert(eql(u8, "abcd", "abcd")); - assert(!eql(u8, "abcdef", "abZdef")); - assert(!eql(u8, "abcdefg", "abcdef")); + testing.expect(eql(u8, "abcd", "abcd")); + testing.expect(!eql(u8, "abcdef", "abZdef")); + testing.expect(!eql(u8, "abcdefg", "abcdef")); } test "testReadInt" { @@ -936,12 +937,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); - assert(readIntBig(u32, &bytes) == 0x12345678); - assert(readIntBig(i32, &bytes) == 0x12345678); - assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); - assert(readIntLittle(u32, &bytes) == 0x78563412); - assert(readIntLittle(i32, &bytes) == 0x78563412); + testing.expect(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + testing.expect(readIntBig(u32, &bytes) == 0x12345678); + testing.expect(readIntBig(i32, &bytes) == 0x12345678); + testing.expect(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + testing.expect(readIntLittle(u32, &bytes) == 0x78563412); + testing.expect(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -951,7 +952,7 @@ fn testReadIntImpl() void { 0x34, }; const answer = readInt(u32, &buf, builtin.Endian.Big); - assert(answer == 0x00001234); + testing.expect(answer == 0x00001234); } { const buf = []u8{ @@ -961,17 +962,17 @@ fn testReadIntImpl() void { 0x00, }; const answer = readInt(u32, &buf, builtin.Endian.Little); - assert(answer == 0x00003412); + testing.expect(answer == 0x00003412); } { const bytes = []u8{ 0xff, 0xfe, }; - assert(readIntBig(u16, &bytes) == 0xfffe); - assert(readIntBig(i16, &bytes) == -0x0002); - assert(readIntLittle(u16, &bytes) == 0xfeff); - assert(readIntLittle(i16, &bytes) == -0x0101); + testing.expect(readIntBig(u16, &bytes) == 0xfffe); + testing.expect(readIntBig(i16, &bytes) == -0x0002); + testing.expect(readIntLittle(u16, &bytes) == 0xfeff); + testing.expect(readIntLittle(i16, &bytes) == -0x0101); } } @@ -983,19 +984,19 @@ fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })); writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })); writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1007,7 +1008,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1019,7 +1020,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, @@ -1031,7 +1032,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1043,7 +1044,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, @@ -1055,7 +1056,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, @@ -1076,7 +1077,7 @@ pub fn min(comptime T: type, slice: []const T) T { } test "mem.min" { - assert(min(u8, "abcdefg") == 'a'); + testing.expect(min(u8, "abcdefg") == 'a'); } pub fn max(comptime T: type, slice: []const T) T { @@ -1088,7 +1089,7 @@ pub fn max(comptime T: type, slice: []const T) T { } test "mem.max" { - assert(max(u8, "abcdefg") == 'g'); + testing.expect(max(u8, "abcdefg") == 'g'); } pub fn swap(comptime T: type, a: *T, b: *T) void { @@ -1116,7 +1117,7 @@ test "std.mem.reverse" { }; reverse(i32, arr[0..]); - assert(eql(i32, arr, []i32{ + testing.expect(eql(i32, arr, []i32{ 4, 2, 1, @@ -1143,7 +1144,7 @@ test "std.mem.rotate" { }; rotate(i32, arr[0..], 2); - assert(eql(i32, arr, []i32{ + testing.expect(eql(i32, arr, []i32{ 1, 2, 4, @@ -1225,12 +1226,12 @@ test "std.mem.asBytes" { builtin.Endian.Little => "\xEF\xBE\xAD\xDE", }; - debug.assert(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); + testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); var codeface = u32(0xC0DEFACE); for (asBytes(&codeface).*) |*b| b.* = 0; - debug.assert(codeface == 0); + testing.expect(codeface == 0); const S = packed struct { a: u8, @@ -1245,7 +1246,7 @@ test "std.mem.asBytes" { .c = 0xDE, .d = 0xA1, }; - debug.assert(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); + testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); } ///Given any value, returns a copy of its bytes in an array. @@ -1256,14 +1257,14 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 { test "std.mem.toBytes" { var my_bytes = toBytes(u32(0x12345678)); switch (builtin.endian) { - builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")), - builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")), + builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")), + builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")), } my_bytes[0] = '\x99'; switch (builtin.endian) { - builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")), - builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")), + builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")), + builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")), } } @@ -1292,17 +1293,17 @@ test "std.mem.bytesAsValue" { builtin.Endian.Little => "\xEF\xBE\xAD\xDE", }; - debug.assert(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*); + testing.expect(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*); var codeface_bytes = switch (builtin.endian) { builtin.Endian.Big => "\xC0\xDE\xFA\xCE", builtin.Endian.Little => "\xCE\xFA\xDE\xC0", }; var codeface = bytesAsValue(u32, &codeface_bytes); - debug.assert(codeface.* == 0xC0DEFACE); + testing.expect(codeface.* == 0xC0DEFACE); codeface.* = 0; for (codeface_bytes) |b| - debug.assert(b == 0); + testing.expect(b == 0); const S = packed struct { a: u8, @@ -1319,7 +1320,7 @@ test "std.mem.bytesAsValue" { }; const inst_bytes = "\xBE\xEF\xDE\xA1"; const inst2 = bytesAsValue(S, &inst_bytes); - debug.assert(meta.eql(inst, inst2.*)); + testing.expect(meta.eql(inst, inst2.*)); } ///Given a pointer to an array of bytes, returns a value of the specified type backed by a @@ -1334,7 +1335,7 @@ test "std.mem.bytesToValue" { }; const deadbeef = bytesToValue(u32, deadbeef_bytes); - debug.assert(deadbeef == u32(0xDEADBEEF)); + testing.expect(deadbeef == u32(0xDEADBEEF)); } fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { @@ -1345,7 +1346,7 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { ///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@typeOf(ptr), length) { - debug.assert(start + length <= ptr.*.len); + assert(start + length <= ptr.*.len); const ReturnType = SubArrayPtrReturnType(@typeOf(ptr), length); const T = meta.Child(meta.Child(@typeOf(ptr))); @@ -1355,14 +1356,14 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA test "std.mem.subArrayPtr" { const a1 = "abcdef"; const sub1 = subArrayPtr(&a1, 2, 3); - debug.assert(std.mem.eql(u8, sub1.*, "cde")); + testing.expect(std.mem.eql(u8, sub1.*, "cde")); var a2 = "abcdef"; var sub2 = subArrayPtr(&a2, 2, 3); - debug.assert(std.mem.eql(u8, sub2, "cde")); + testing.expect(std.mem.eql(u8, sub2, "cde")); sub2[1] = 'X'; - debug.assert(std.mem.eql(u8, a2, "abcXef")); + testing.expect(std.mem.eql(u8, a2, "abcXef")); } /// Round an address up to the nearest aligned address @@ -1371,16 +1372,16 @@ pub fn alignForward(addr: usize, alignment: usize) usize { } test "std.mem.alignForward" { - debug.assertOrPanic(alignForward(1, 1) == 1); - debug.assertOrPanic(alignForward(2, 1) == 2); - debug.assertOrPanic(alignForward(1, 2) == 2); - debug.assertOrPanic(alignForward(2, 2) == 2); - debug.assertOrPanic(alignForward(3, 2) == 4); - debug.assertOrPanic(alignForward(4, 2) == 4); - debug.assertOrPanic(alignForward(7, 8) == 8); - debug.assertOrPanic(alignForward(8, 8) == 8); - debug.assertOrPanic(alignForward(9, 8) == 16); - debug.assertOrPanic(alignForward(15, 8) == 16); - debug.assertOrPanic(alignForward(16, 8) == 16); - debug.assertOrPanic(alignForward(17, 8) == 24); + testing.expect(alignForward(1, 1) == 1); + testing.expect(alignForward(2, 1) == 2); + testing.expect(alignForward(1, 2) == 2); + testing.expect(alignForward(2, 2) == 2); + testing.expect(alignForward(3, 2) == 4); + testing.expect(alignForward(4, 2) == 4); + testing.expect(alignForward(7, 8) == 8); + testing.expect(alignForward(8, 8) == 8); + testing.expect(alignForward(9, 8) == 16); + testing.expect(alignForward(15, 8) == 16); + testing.expect(alignForward(16, 8) == 16); + testing.expect(alignForward(17, 8) == 24); } diff --git a/std/meta/index.zig b/std/meta/index.zig index 4d195a6a12..3f8ea762a6 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -3,6 +3,7 @@ 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"); @@ -64,16 +65,16 @@ test "std.meta.tagName" { var u2a = U2{ .C = 0 }; var u2b = U2{ .D = 0 }; - debug.assert(mem.eql(u8, tagName(E1.A), "A")); - debug.assert(mem.eql(u8, tagName(E1.B), "B")); - debug.assert(mem.eql(u8, tagName(E2.C), "C")); - debug.assert(mem.eql(u8, tagName(E2.D), "D")); - debug.assert(mem.eql(u8, tagName(error.E), "E")); - debug.assert(mem.eql(u8, tagName(error.F), "F")); - debug.assert(mem.eql(u8, tagName(u1g), "G")); - debug.assert(mem.eql(u8, tagName(u1h), "H")); - debug.assert(mem.eql(u8, tagName(u2a), "C")); - debug.assert(mem.eql(u8, tagName(u2b), "D")); + 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 { @@ -90,9 +91,9 @@ test "std.meta.stringToEnum" { A, B, }; - debug.assert(E1.A == stringToEnum(E1, "A").?); - debug.assert(E1.B == stringToEnum(E1, "B").?); - debug.assert(null == stringToEnum(E1, "C")); + 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 { @@ -104,8 +105,8 @@ pub fn bitCount(comptime T: type) comptime_int { } test "std.meta.bitCount" { - debug.assert(bitCount(u8) == 8); - debug.assert(bitCount(f32) == 32); + testing.expect(bitCount(u8) == 8); + testing.expect(bitCount(f32) == 32); } pub fn alignment(comptime T: type) comptime_int { @@ -115,11 +116,11 @@ pub fn alignment(comptime T: type) comptime_int { } test "std.meta.alignment" { - debug.assert(alignment(u8) == 1); - debug.assert(alignment(*align(1) u8) == 1); - debug.assert(alignment(*align(2) u8) == 2); - debug.assert(alignment([]align(1) u8) == 1); - debug.assert(alignment([]align(2) u8) == 2); + 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 { @@ -133,11 +134,11 @@ pub fn Child(comptime T: type) type { } test "std.meta.Child" { - debug.assert(Child([1]u8) == u8); - debug.assert(Child(*u8) == u8); - debug.assert(Child([]u8) == u8); - debug.assert(Child(?u8) == u8); - debug.assert(Child(promise->u8) == u8); + 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 { @@ -172,15 +173,15 @@ test "std.meta.containerLayout" { a: u8, }; - debug.assert(containerLayout(E1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(E2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(E3) == TypeInfo.ContainerLayout.Extern); - debug.assert(containerLayout(S1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(S2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(S3) == TypeInfo.ContainerLayout.Extern); - debug.assert(containerLayout(U1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(U2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(U3) == TypeInfo.ContainerLayout.Extern); + 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 { @@ -214,8 +215,8 @@ test "std.meta.definitions" { }; inline for (defs) |def| { - debug.assert(def.len == 1); - debug.assert(comptime mem.eql(u8, def[0].name, "a")); + testing.expect(def.len == 1); + testing.expect(comptime mem.eql(u8, def[0].name, "a")); } } @@ -250,8 +251,8 @@ test "std.meta.definitionInfo" { }; inline for (infos) |info| { - debug.assert(comptime mem.eql(u8, info.name, "a")); - debug.assert(!info.is_pub); + testing.expect(comptime mem.eql(u8, info.name, "a")); + testing.expect(!info.is_pub); } } @@ -288,16 +289,16 @@ test "std.meta.fields" { const sf = comptime fields(S1); const uf = comptime fields(U1); - debug.assert(e1f.len == 1); - debug.assert(e2f.len == 1); - debug.assert(sf.len == 1); - debug.assert(uf.len == 1); - debug.assert(mem.eql(u8, e1f[0].name, "A")); - debug.assert(mem.eql(u8, e2f[0].name, "A")); - debug.assert(mem.eql(u8, sf[0].name, "a")); - debug.assert(mem.eql(u8, uf[0].name, "a")); - debug.assert(comptime sf[0].field_type == u8); - debug.assert(comptime uf[0].field_type == u8); + 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)) { @@ -332,12 +333,12 @@ test "std.meta.fieldInfo" { const sf = comptime fieldInfo(S1, "a"); const uf = comptime fieldInfo(U1, "a"); - debug.assert(mem.eql(u8, e1f.name, "A")); - debug.assert(mem.eql(u8, e2f.name, "A")); - debug.assert(mem.eql(u8, sf.name, "a")); - debug.assert(mem.eql(u8, uf.name, "a")); - debug.assert(comptime sf.field_type == u8); - debug.assert(comptime uf.field_type == u8); + 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 { @@ -358,8 +359,8 @@ test "std.meta.TagType" { D: u16, }; - debug.assert(TagType(E) == u8); - debug.assert(TagType(U) == E); + testing.expect(TagType(E) == u8); + testing.expect(TagType(U) == E); } ///Returns the active tag of a tagged union @@ -380,18 +381,18 @@ test "std.meta.activeTag" { }; var u = U{ .Int = 32 }; - debug.assert(activeTag(u) == UE.Int); + testing.expect(activeTag(u) == UE.Int); u = U{ .Float = 112.9876 }; - debug.assert(activeTag(u) == UE.Float); + 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); - debug.assert(trait.is(builtin.TypeId.Union)(U)); - debug.assert(trait.is(builtin.TypeId.Enum)(Tag)); + testing.expect(trait.is(builtin.TypeId.Union)(U)); + testing.expect(trait.is(builtin.TypeId.Enum)(Tag)); const info = @typeInfo(U).Union; @@ -410,7 +411,7 @@ test "std.meta.TagPayloadType" { }; const MovedEvent = TagPayloadType(Event, Event.Moved); var e: Event = undefined; - debug.assert(MovedEvent == @typeOf(e.Moved)); + testing.expect(MovedEvent == @typeOf(e.Moved)); } ///Compares two of any type for equality. Containers are compared on a field-by-field basis, @@ -509,19 +510,19 @@ test "std.meta.eql" { const u_2 = U{ .s = s_1 }; const u_3 = U{ .f = 24 }; - debug.assert(eql(s_1, s_3)); - debug.assert(eql(&s_1, &s_1)); - debug.assert(!eql(&s_1, &s_3)); - debug.assert(eql(u_1, u_3)); - debug.assert(!eql(u_1, u_2)); + 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"; - debug.assert(eql(a1, a2)); - debug.assert(!eql(a1, a3)); - debug.assert(!eql(a1[0..], a2[0..])); + 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 { @@ -530,9 +531,9 @@ test "std.meta.eql" { } }; - debug.assert(eql(EU.tst(true), EU.tst(true))); - debug.assert(eql(EU.tst(false), EU.tst(false))); - debug.assert(!eql(EU.tst(false), EU.tst(true))); + 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" { @@ -546,9 +547,9 @@ test "intToEnum with error return" { var zero: u8 = 0; var one: u16 = 1; - debug.assert(intToEnum(E1, zero) catch unreachable == E1.A); - debug.assert(intToEnum(E2, one) catch unreachable == E2.B); - debug.assertError(intToEnum(E1, one), error.InvalidEnumTag); + 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}; diff --git a/std/meta/trait.zig b/std/meta/trait.zig index c9d9e971c9..7fca5f4dcd 100644 --- a/std/meta/trait.zig +++ b/std/meta/trait.zig @@ -2,6 +2,7 @@ const std = @import("../index.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"); @@ -50,8 +51,8 @@ test "std.meta.trait.multiTrait" { hasField("x"), hasField("y"), }); - debug.assert(isVector(Vector2)); - debug.assert(!isVector(u8)); + testing.expect(isVector(Vector2)); + testing.expect(!isVector(u8)); } /// @@ -85,12 +86,12 @@ test "std.meta.trait.hasDef" { const value = u8(16); }; - debug.assert(hasDef("value")(TestStruct)); - debug.assert(!hasDef("value")(TestStructFail)); - debug.assert(!hasDef("value")(*TestStruct)); - debug.assert(!hasDef("value")(**TestStructFail)); - debug.assert(!hasDef("x")(TestStruct)); - debug.assert(!hasDef("value")(u8)); + testing.expect(hasDef("value")(TestStruct)); + testing.expect(!hasDef("value")(TestStructFail)); + testing.expect(!hasDef("value")(*TestStruct)); + testing.expect(!hasDef("value")(**TestStructFail)); + testing.expect(!hasDef("x")(TestStruct)); + testing.expect(!hasDef("value")(u8)); } /// @@ -111,9 +112,9 @@ test "std.meta.trait.hasFn" { pub fn useless() void {} }; - debug.assert(hasFn("useless")(TestStruct)); - debug.assert(!hasFn("append")(TestStruct)); - debug.assert(!hasFn("useless")(u8)); + testing.expect(hasFn("useless")(TestStruct)); + testing.expect(!hasFn("append")(TestStruct)); + testing.expect(!hasFn("useless")(u8)); } /// @@ -143,11 +144,11 @@ test "std.meta.trait.hasField" { value: u32, }; - debug.assert(hasField("value")(TestStruct)); - debug.assert(!hasField("value")(*TestStruct)); - debug.assert(!hasField("x")(TestStruct)); - debug.assert(!hasField("x")(**TestStruct)); - debug.assert(!hasField("value")(u8)); + testing.expect(hasField("value")(TestStruct)); + testing.expect(!hasField("value")(*TestStruct)); + testing.expect(!hasField("x")(TestStruct)); + testing.expect(!hasField("x")(**TestStruct)); + testing.expect(!hasField("value")(u8)); } /// @@ -161,11 +162,11 @@ pub fn is(comptime id: builtin.TypeId) TraitFn { } test "std.meta.trait.is" { - debug.assert(is(builtin.TypeId.Int)(u8)); - debug.assert(!is(builtin.TypeId.Int)(f32)); - debug.assert(is(builtin.TypeId.Pointer)(*u8)); - debug.assert(is(builtin.TypeId.Void)(void)); - debug.assert(!is(builtin.TypeId.Optional)(anyerror)); + testing.expect(is(builtin.TypeId.Int)(u8)); + testing.expect(!is(builtin.TypeId.Int)(f32)); + testing.expect(is(builtin.TypeId.Pointer)(*u8)); + testing.expect(is(builtin.TypeId.Void)(void)); + testing.expect(!is(builtin.TypeId.Optional)(anyerror)); } /// @@ -180,9 +181,9 @@ pub fn isPtrTo(comptime id: builtin.TypeId) TraitFn { } test "std.meta.trait.isPtrTo" { - debug.assert(!isPtrTo(builtin.TypeId.Struct)(struct {})); - debug.assert(isPtrTo(builtin.TypeId.Struct)(*struct {})); - debug.assert(!isPtrTo(builtin.TypeId.Struct)(**struct {})); + testing.expect(!isPtrTo(builtin.TypeId.Struct)(struct {})); + testing.expect(isPtrTo(builtin.TypeId.Struct)(*struct {})); + testing.expect(!isPtrTo(builtin.TypeId.Struct)(**struct {})); } ///////////Strait trait Fns @@ -205,9 +206,9 @@ test "std.meta.trait.isExtern" { const TestExStruct = extern struct {}; const TestStruct = struct {}; - debug.assert(isExtern(TestExStruct)); - debug.assert(!isExtern(TestStruct)); - debug.assert(!isExtern(u8)); + testing.expect(isExtern(TestExStruct)); + testing.expect(!isExtern(TestStruct)); + testing.expect(!isExtern(u8)); } /// @@ -226,9 +227,9 @@ test "std.meta.trait.isPacked" { const TestPStruct = packed struct {}; const TestStruct = struct {}; - debug.assert(isPacked(TestPStruct)); - debug.assert(!isPacked(TestStruct)); - debug.assert(!isPacked(u8)); + testing.expect(isPacked(TestPStruct)); + testing.expect(!isPacked(TestStruct)); + testing.expect(!isPacked(u8)); } /// @@ -240,10 +241,10 @@ pub fn isUnsignedInt(comptime T: type) bool { } test "isUnsignedInt" { - debug.assert(isUnsignedInt(u32) == true); - debug.assert(isUnsignedInt(comptime_int) == false); - debug.assert(isUnsignedInt(i64) == false); - debug.assert(isUnsignedInt(f64) == false); + testing.expect(isUnsignedInt(u32) == true); + testing.expect(isUnsignedInt(comptime_int) == false); + testing.expect(isUnsignedInt(i64) == false); + testing.expect(isUnsignedInt(f64) == false); } /// @@ -256,10 +257,10 @@ pub fn isSignedInt(comptime T: type) bool { } test "isSignedInt" { - debug.assert(isSignedInt(u32) == false); - debug.assert(isSignedInt(comptime_int) == true); - debug.assert(isSignedInt(i64) == true); - debug.assert(isSignedInt(f64) == false); + testing.expect(isSignedInt(u32) == false); + testing.expect(isSignedInt(comptime_int) == true); + testing.expect(isSignedInt(i64) == true); + testing.expect(isSignedInt(f64) == false); } /// @@ -273,9 +274,9 @@ pub fn isSingleItemPtr(comptime T: type) bool { test "std.meta.trait.isSingleItemPtr" { const array = []u8{0} ** 10; - debug.assert(isSingleItemPtr(@typeOf(&array[0]))); - debug.assert(!isSingleItemPtr(@typeOf(array))); - debug.assert(!isSingleItemPtr(@typeOf(array[0..1]))); + testing.expect(isSingleItemPtr(@typeOf(&array[0]))); + testing.expect(!isSingleItemPtr(@typeOf(array))); + testing.expect(!isSingleItemPtr(@typeOf(array[0..1]))); } /// @@ -290,9 +291,9 @@ pub fn isManyItemPtr(comptime T: type) bool { test "std.meta.trait.isManyItemPtr" { const array = []u8{0} ** 10; const mip = @ptrCast([*]const u8, &array[0]); - debug.assert(isManyItemPtr(@typeOf(mip))); - debug.assert(!isManyItemPtr(@typeOf(array))); - debug.assert(!isManyItemPtr(@typeOf(array[0..1]))); + testing.expect(isManyItemPtr(@typeOf(mip))); + testing.expect(!isManyItemPtr(@typeOf(array))); + testing.expect(!isManyItemPtr(@typeOf(array[0..1]))); } /// @@ -306,9 +307,9 @@ pub fn isSlice(comptime T: type) bool { test "std.meta.trait.isSlice" { const array = []u8{0} ** 10; - debug.assert(isSlice(@typeOf(array[0..]))); - debug.assert(!isSlice(@typeOf(array))); - debug.assert(!isSlice(@typeOf(&array[0]))); + testing.expect(isSlice(@typeOf(array[0..]))); + testing.expect(!isSlice(@typeOf(array))); + testing.expect(!isSlice(@typeOf(&array[0]))); } /// @@ -328,10 +329,10 @@ test "std.meta.trait.isIndexable" { const array = []u8{0} ** 10; const slice = array[0..]; - debug.assert(isIndexable(@typeOf(array))); - debug.assert(isIndexable(@typeOf(&array))); - debug.assert(isIndexable(@typeOf(slice))); - debug.assert(!isIndexable(meta.Child(@typeOf(slice)))); + testing.expect(isIndexable(@typeOf(array))); + testing.expect(isIndexable(@typeOf(&array))); + testing.expect(isIndexable(@typeOf(slice))); + testing.expect(!isIndexable(meta.Child(@typeOf(slice)))); } /// @@ -347,13 +348,13 @@ test "std.meta.trait.isNumber" { number: u8, }; - debug.assert(isNumber(u32)); - debug.assert(isNumber(f32)); - debug.assert(isNumber(u64)); - debug.assert(isNumber(@typeOf(102))); - debug.assert(isNumber(@typeOf(102.123))); - debug.assert(!isNumber([]u8)); - debug.assert(!isNumber(NotANumber)); + testing.expect(isNumber(u32)); + testing.expect(isNumber(f32)); + testing.expect(isNumber(u64)); + testing.expect(isNumber(@typeOf(102))); + testing.expect(isNumber(@typeOf(102.123))); + testing.expect(!isNumber([]u8)); + testing.expect(!isNumber(NotANumber)); } /// @@ -366,10 +367,10 @@ pub fn isConstPtr(comptime T: type) bool { test "std.meta.trait.isConstPtr" { var t = u8(0); const c = u8(0); - debug.assert(isConstPtr(*const @typeOf(t))); - debug.assert(isConstPtr(@typeOf(&c))); - debug.assert(!isConstPtr(*@typeOf(t))); - debug.assert(!isConstPtr(@typeOf(6))); + testing.expect(isConstPtr(*const @typeOf(t))); + testing.expect(isConstPtr(@typeOf(&c))); + testing.expect(!isConstPtr(*@typeOf(t))); + testing.expect(!isConstPtr(@typeOf(6))); } /// @@ -393,8 +394,8 @@ test "std.meta.trait.isContainer" { B, }; - debug.assert(isContainer(TestStruct)); - debug.assert(isContainer(TestUnion)); - debug.assert(isContainer(TestEnum)); - debug.assert(!isContainer(u8)); + testing.expect(isContainer(TestStruct)); + testing.expect(isContainer(TestUnion)); + testing.expect(isContainer(TestEnum)); + testing.expect(!isContainer(u8)); } diff --git a/std/mutex.zig b/std/mutex.zig index 54173fa38a..a13b1c06c7 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; -const assert = std.debug.assert; +const testing = std.testing; const SpinLock = std.SpinLock; const linux = std.os.linux; const windows = std.os.windows; @@ -149,7 +149,7 @@ test "std.Mutex" { if (builtin.single_threaded) { worker(&context); - std.debug.assertOrPanic(context.data == TestContext.incr_count); + testing.expect(context.data == TestContext.incr_count); } else { const thread_count = 10; var threads: [thread_count]*std.os.Thread = undefined; @@ -159,7 +159,7 @@ test "std.Mutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + testing.expect(context.data == thread_count * TestContext.incr_count); } } diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 6635b76976..1da0b3492b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -7,7 +7,6 @@ const posix = os.posix; const windows = os.windows; const mem = std.mem; const debug = std.debug; -const assert = debug.assert; const BufMap = std.BufMap; const Buffer = std.Buffer; const builtin = @import("builtin"); diff --git a/std/os/index.zig b/std/os/index.zig index 8e9876c36b..f52c12c2b6 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -91,6 +91,7 @@ pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirErro const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const c = std.c; @@ -172,7 +173,7 @@ test "os.getRandomBytes" { try getRandomBytes(buf_b[0..]); // Check if random (not 100% conclusive) - assert(!mem.eql(u8, buf_a, buf_b)); + testing.expect(!mem.eql(u8, buf_a, buf_b)); } /// Raises a signal in the current kernel thread, ending its execution. @@ -828,7 +829,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned test "os.getEnvVarOwned" { var ga = debug.global_allocator; - debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); + testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); } /// Caller must free the returned memory. @@ -2219,9 +2220,9 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { const arg = it.next(debug.global_allocator).? catch unreachable; - assert(mem.eql(u8, arg, expected_arg)); + testing.expectEqualSlices(u8, expected_arg, arg); } - assert(it.next(debug.global_allocator) == null); + testing.expect(it.next(debug.global_allocator) == null); } // TODO make this a build variable that you can set diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig index 4de26012c7..40fb7823d2 100644 --- a/std/os/linux/test.zig +++ b/std/os/linux/test.zig @@ -1,19 +1,19 @@ const std = @import("../../index.zig"); const builtin = @import("builtin"); const linux = std.os.linux; -const assert = std.debug.assert; +const expect = std.testing.expect; test "getpid" { - assert(linux.getpid() != 0); + expect(linux.getpid() != 0); } test "timer" { const epoll_fd = linux.epoll_create(); var err = linux.getErrno(epoll_fd); - assert(err == 0); + expect(err == 0); const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0); - assert(linux.getErrno(timer_fd) == 0); + expect(linux.getErrno(timer_fd) == 0); const time_interval = linux.timespec{ .tv_sec = 0, @@ -26,7 +26,7 @@ test "timer" { }; err = linux.timerfd_settime(@intCast(i32, timer_fd), 0, &new_time, null); - assert(err == 0); + expect(err == 0); var event = linux.epoll_event{ .events = linux.EPOLLIN | linux.EPOLLOUT | linux.EPOLLET, @@ -34,7 +34,7 @@ test "timer" { }; err = linux.epoll_ctl(@intCast(i32, epoll_fd), linux.EPOLL_CTL_ADD, @intCast(i32, timer_fd), &event); - assert(err == 0); + expect(err == 0); const events_one: linux.epoll_event = undefined; var events = []linux.epoll_event{events_one} ** 8; diff --git a/std/os/path.zig b/std/os/path.zig index 266a77b97c..5ba345fceb 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const fmt = std.fmt; const Allocator = mem.Allocator; @@ -94,14 +95,14 @@ fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; const actual = joinWindows(a, paths) catch @panic("fail"); - debug.assertOrPanic(mem.eql(u8, actual, expected)); + testing.expectEqualSlices(u8, expected, actual); } fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; const actual = joinPosix(a, paths) catch @panic("fail"); - debug.assertOrPanic(mem.eql(u8, actual, expected)); + testing.expectEqualSlices(u8, expected, actual); } test "os.path.join" { @@ -193,11 +194,11 @@ test "os.path.isAbsolutePosix" { } fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void { - assert(isAbsoluteWindows(path) == expected_result); + testing.expectEqual(expected_result, isAbsoluteWindows(path)); } fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void { - assert(isAbsolutePosix(path) == expected_result); + testing.expectEqual(expected_result, isAbsolutePosix(path)); } pub const WindowsPath = struct { @@ -281,33 +282,33 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { test "os.path.windowsParsePath" { { const parsed = windowsParsePath("//a/b"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.NetworkShare); - assert(mem.eql(u8, parsed.disk_designator, "//a/b")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare); + testing.expect(mem.eql(u8, parsed.disk_designator, "//a/b")); } { const parsed = windowsParsePath("\\\\a\\b"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.NetworkShare); - assert(mem.eql(u8, parsed.disk_designator, "\\\\a\\b")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare); + testing.expect(mem.eql(u8, parsed.disk_designator, "\\\\a\\b")); } { const parsed = windowsParsePath("\\\\a\\"); - assert(!parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.None); - assert(mem.eql(u8, parsed.disk_designator, "")); + testing.expect(!parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.None); + testing.expect(mem.eql(u8, parsed.disk_designator, "")); } { const parsed = windowsParsePath("/usr/local"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.None); - assert(mem.eql(u8, parsed.disk_designator, "")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.None); + testing.expect(mem.eql(u8, parsed.disk_designator, "")); } { const parsed = windowsParsePath("c:../"); - assert(!parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.Drive); - assert(mem.eql(u8, parsed.disk_designator, "c:")); + testing.expect(!parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.Drive); + testing.expect(mem.eql(u8, parsed.disk_designator, "c:")); } } @@ -642,10 +643,10 @@ test "os.path.resolve" { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); } - assert(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd)); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd)); } else { - assert(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd)); - assert(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd)); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd)); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd)); } } @@ -662,7 +663,7 @@ test "os.path.resolveWindows" { if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - assert(mem.eql(u8, result, expected)); + testing.expect(mem.eql(u8, result, expected)); } { const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" }); @@ -673,36 +674,36 @@ test "os.path.resolveWindows" { if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - assert(mem.eql(u8, result, expected)); + testing.expect(mem.eql(u8, result, expected)); } } - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js")); } test "os.path.resolvePosix" { - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/")); - assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js")); } fn testResolveWindows(paths: []const []const u8) []u8 { @@ -833,17 +834,17 @@ test "os.path.dirnameWindows" { fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void { if (dirnamePosix(input)) |output| { - assert(mem.eql(u8, output, expected_output.?)); + testing.expect(mem.eql(u8, output, expected_output.?)); } else { - assert(expected_output == null); + testing.expect(expected_output == null); } } fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void { if (dirnameWindows(input)) |output| { - assert(mem.eql(u8, output, expected_output.?)); + testing.expect(mem.eql(u8, output, expected_output.?)); } else { - assert(expected_output == null); + testing.expect(expected_output == null); } } @@ -948,15 +949,15 @@ test "os.path.basename" { } fn testBasename(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basename(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basename(input)); } fn testBasenamePosix(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basenamePosix(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basenamePosix(input)); } fn testBasenameWindows(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basenameWindows(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basenameWindows(input)); } /// Returns the relative path from `from` to `to`. If `from` and `to` each @@ -1131,12 +1132,12 @@ test "os.path.relative" { fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void { const result = relativePosix(debug.global_allocator, from, to) catch unreachable; - assert(mem.eql(u8, result, expected_output)); + testing.expectEqualSlices(u8, expected_output, result); } fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void { const result = relativeWindows(debug.global_allocator, from, to) catch unreachable; - assert(mem.eql(u8, result, expected_output)); + testing.expectEqualSlices(u8, expected_output, result); } pub const RealError = error{ @@ -1283,5 +1284,5 @@ pub fn realAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { test "os.path.real" { // at least call it so it gets compiled var buf: [os.MAX_PATH_BYTES]u8 = undefined; - std.debug.assertError(real(&buf, "definitely_bogus_does_not_exist1234"), error.FileNotFound); + testing.expectError(error.FileNotFound, real(&buf, "definitely_bogus_does_not_exist1234")); } diff --git a/std/os/test.zig b/std/os/test.zig index bd9148d1b1..b2a4d96651 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const os = std.os; -const assert = std.debug.assert; +const expect = std.testing.expect; const io = std.io; const mem = std.mem; @@ -18,7 +18,7 @@ test "makePath, put some files in it, deleteTree" { if (os.Dir.open(a, "os_test_tmp")) |dir| { @panic("expected error"); } else |err| { - assert(err == error.FileNotFound); + expect(err == error.FileNotFound); } } @@ -27,7 +27,7 @@ test "access file" { if (os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt")) |ok| { @panic("expected error"); } else |err| { - assert(err == error.FileNotFound); + expect(err == error.FileNotFound); } try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "file.txt", ""); @@ -47,9 +47,9 @@ test "std.os.Thread.getCurrentId" { const thread_id = thread.handle(); thread.wait(); switch (builtin.os) { - builtin.Os.windows => assert(os.Thread.getCurrentId() != thread_current_id), + builtin.Os.windows => expect(os.Thread.getCurrentId() != thread_current_id), else => { - assert(thread_current_id == thread_id); + expect(thread_current_id == thread_id); }, } } @@ -69,7 +69,7 @@ test "spawn threads" { thread3.wait(); thread4.wait(); - assert(shared_ctx == 4); + expect(shared_ctx == 4); } fn start1(ctx: void) u8 { @@ -83,7 +83,7 @@ fn start2(ctx: *i32) u8 { test "cpu count" { const cpu_count = try std.os.cpuCount(a); - assert(cpu_count >= 1); + expect(cpu_count >= 1); } test "AtomicFile" { @@ -101,7 +101,7 @@ test "AtomicFile" { try af.finish(); } const content = try io.readFileAlloc(allocator, test_out_file); - assert(mem.eql(u8, content, test_content)); + expect(mem.eql(u8, content, test_content)); try os.deleteFile(test_out_file); } diff --git a/std/os/time.zig b/std/os/time.zig index 4b11a69376..638fb41ff1 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -2,6 +2,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; +const testing = std.testing; const windows = std.os.windows; const linux = std.os.linux; @@ -270,7 +271,7 @@ test "os.time.timestamp" { sleep(ns_per_ms); const time_1 = milliTimestamp(); const interval = time_1 - time_0; - debug.assert(interval > 0 and interval < margin); + testing.expect(interval > 0 and interval < margin); } test "os.time.Timer" { @@ -280,11 +281,11 @@ test "os.time.Timer" { var timer = try Timer.start(); sleep(10 * ns_per_ms); const time_0 = timer.read(); - debug.assert(time_0 > 0 and time_0 < margin); + testing.expect(time_0 > 0 and time_0 < margin); const time_1 = timer.lap(); - debug.assert(time_1 >= time_0); + testing.expect(time_1 >= time_0); timer.reset(); - debug.assert(timer.read() < time_1); + testing.expect(timer.read() < time_1); } diff --git a/std/rand/index.zig b/std/rand/index.zig index c335063e64..12dd763aee 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -17,6 +17,7 @@ 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"); @@ -316,43 +317,43 @@ test "Random int" { fn testRandomInt() void { var r = SequentialPrng.init(); - assert(r.random.int(u0) == 0); + expect(r.random.int(u0) == 0); r.next_value = 0; - assert(r.random.int(u1) == 0); - assert(r.random.int(u1) == 1); - assert(r.random.int(u2) == 2); - assert(r.random.int(u2) == 3); - assert(r.random.int(u2) == 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; - assert(r.random.int(u8) == 0xff); + expect(r.random.int(u8) == 0xff); r.next_value = 0x11; - assert(r.random.int(u8) == 0x11); + expect(r.random.int(u8) == 0x11); r.next_value = 0xff; - assert(r.random.int(u32) == 0xffffffff); + expect(r.random.int(u32) == 0xffffffff); r.next_value = 0x11; - assert(r.random.int(u32) == 0x11111111); + expect(r.random.int(u32) == 0x11111111); r.next_value = 0xff; - assert(r.random.int(i32) == -1); + expect(r.random.int(i32) == -1); r.next_value = 0x11; - assert(r.random.int(i32) == 0x11111111); + expect(r.random.int(i32) == 0x11111111); r.next_value = 0xff; - assert(r.random.int(i8) == -1); + expect(r.random.int(i8) == -1); r.next_value = 0x11; - assert(r.random.int(i8) == 0x11); + expect(r.random.int(i8) == 0x11); r.next_value = 0xff; - assert(r.random.int(u33) == 0x1ffffffff); + expect(r.random.int(u33) == 0x1ffffffff); r.next_value = 0xff; - assert(r.random.int(i1) == -1); + expect(r.random.int(i1) == -1); r.next_value = 0xff; - assert(r.random.int(i2) == -1); + expect(r.random.int(i2) == -1); r.next_value = 0xff; - assert(r.random.int(i33) == -1); + expect(r.random.int(i33) == -1); } test "Random boolean" { @@ -361,10 +362,10 @@ test "Random boolean" { } fn testRandomBoolean() void { var r = SequentialPrng.init(); - assert(r.random.boolean() == false); - assert(r.random.boolean() == true); - assert(r.random.boolean() == false); - assert(r.random.boolean() == true); + expect(r.random.boolean() == false); + expect(r.random.boolean() == true); + expect(r.random.boolean() == false); + expect(r.random.boolean() == true); } test "Random intLessThan" { @@ -375,36 +376,36 @@ test "Random intLessThan" { fn testRandomIntLessThan() void { var r = SequentialPrng.init(); r.next_value = 0xff; - assert(r.random.uintLessThan(u8, 4) == 3); - assert(r.next_value == 0); - assert(r.random.uintLessThan(u8, 4) == 0); - assert(r.next_value == 1); + 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; - assert(r.random.uintLessThan(u64, 32) == 0); + expect(r.random.uintLessThan(u64, 32) == 0); // trigger the bias rejection code path r.next_value = 0; - assert(r.random.uintLessThan(u8, 3) == 0); + expect(r.random.uintLessThan(u8, 3) == 0); // verify we incremented twice - assert(r.next_value == 2); + expect(r.next_value == 2); r.next_value = 0xff; - assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); + expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe); + expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f); + expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f); + expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1); + expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i3, -4, 0) == -1); + expect(r.random.intRangeLessThan(i3, -4, 0) == -1); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i3, -2, 2) == 1); + expect(r.random.intRangeLessThan(i3, -2, 2) == 1); } test "Random intAtMost" { @@ -415,34 +416,34 @@ test "Random intAtMost" { fn testRandomIntAtMost() void { var r = SequentialPrng.init(); r.next_value = 0xff; - assert(r.random.uintAtMost(u8, 3) == 3); - assert(r.next_value == 0); - assert(r.random.uintAtMost(u8, 3) == 0); + 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; - assert(r.random.uintAtMost(u8, 2) == 0); + expect(r.random.uintAtMost(u8, 2) == 0); // verify we incremented twice - assert(r.next_value == 2); + expect(r.next_value == 2); r.next_value = 0xff; - assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); + expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe); + expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f); + expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f); + expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1); + expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i3, -4, -1) == -1); + expect(r.random.intRangeAtMost(i3, -4, -1) == -1); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i3, -2, 1) == 1); + expect(r.random.intRangeAtMost(i3, -2, 1) == 1); - assert(r.random.uintAtMost(u0, 0) == 0); + expect(r.random.uintAtMost(u0, 0) == 0); } test "Random Biased" { @@ -450,30 +451,30 @@ test "Random Biased" { // Not thoroughly checking the logic here. // Just want to execute all the paths with different types. - assert(r.random.uintLessThanBiased(u1, 1) == 0); - assert(r.random.uintLessThanBiased(u32, 10) < 10); - assert(r.random.uintLessThanBiased(u64, 20) < 20); + expect(r.random.uintLessThanBiased(u1, 1) == 0); + expect(r.random.uintLessThanBiased(u32, 10) < 10); + expect(r.random.uintLessThanBiased(u64, 20) < 20); - assert(r.random.uintAtMostBiased(u0, 0) == 0); - assert(r.random.uintAtMostBiased(u1, 0) <= 0); - assert(r.random.uintAtMostBiased(u32, 10) <= 10); - assert(r.random.uintAtMostBiased(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); - assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0); - assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1); - assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10); - assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10); - assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20); - assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 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: - //assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0); - assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0); - assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1); - assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10); - assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10); - assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20); - assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20); + //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. @@ -510,7 +511,7 @@ test "splitmix64 sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -603,7 +604,7 @@ test "pcg sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -712,7 +713,7 @@ test "xoroshiro sequence" { }; for (seq1) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } r.jump(); @@ -727,7 +728,7 @@ test "xoroshiro sequence" { }; for (seq2) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -930,7 +931,7 @@ test "isaac64 sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -941,12 +942,12 @@ test "Random float" { var i: usize = 0; while (i < 1000) : (i += 1) { const val1 = prng.random.float(f32); - std.debug.assert(val1 >= 0.0); - std.debug.assert(val1 < 1.0); + expect(val1 >= 0.0); + expect(val1 < 1.0); const val2 = prng.random.float(f64); - std.debug.assert(val2 >= 0.0); - std.debug.assert(val2 < 1.0); + expect(val2 >= 0.0); + expect(val2 < 1.0); } } @@ -960,12 +961,12 @@ test "Random shuffle" { while (i < 1000) : (i += 1) { prng.random.shuffle(u8, seq[0..]); seen[seq[0]] = true; - std.debug.assert(sumArray(seq[0..]) == 10); + expect(sumArray(seq[0..]) == 10); } // we should see every entry at the head at least once for (seen) |e| { - std.debug.assert(e == true); + expect(e == true); } } diff --git a/std/rb.zig b/std/rb.zig index beb7f3aae9..27e60dca6a 100644 --- a/std/rb.zig +++ b/std/rb.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; // For mem.Compare const Color = enum(u1) { @@ -533,13 +534,13 @@ test "rb" { _ = tree.insert(&ns[8].node); _ = tree.insert(&ns[9].node); tree.remove(&ns[3].node); - assert(tree.insert(&dup.node) == &ns[7].node); + testing.expect(tree.insert(&dup.node) == &ns[7].node); try tree.replace(&ns[7].node, &dup.node); var num: *testNumber = undefined; num = testGetNumber(tree.first().?); while (num.node.next() != null) { - assert(testGetNumber(num.node.next().?).value > num.value); + testing.expect(testGetNumber(num.node.next().?).value > num.value); num = testGetNumber(num.node.next().?); } } diff --git a/std/segmented_list.zig b/std/segmented_list.zig index d786e0becd..26b7fa48f5 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const Allocator = std.mem.Allocator; // Imagine that `fn at(self: *Self, index: usize) &T` is a customer asking for a box @@ -352,14 +353,14 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { var i: usize = 0; while (i < 100) : (i += 1) { try list.push(@intCast(i32, i + 1)); - assert(list.len == i + 1); + testing.expect(list.len == i + 1); } } { var i: usize = 0; while (i < 100) : (i += 1) { - assert(list.at(i).* == @intCast(i32, i + 1)); + testing.expect(list.at(i).* == @intCast(i32, i + 1)); } } @@ -368,35 +369,35 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { var x: i32 = 0; while (it.next()) |item| { x += 1; - assert(item.* == x); + testing.expect(item.* == x); } - assert(x == 100); + testing.expect(x == 100); while (it.prev()) |item| : (x -= 1) { - assert(item.* == x); + testing.expect(item.* == x); } - assert(x == 0); + testing.expect(x == 0); } - assert(list.pop().? == 100); - assert(list.len == 99); + testing.expect(list.pop().? == 100); + testing.expect(list.len == 99); try list.pushMany([]i32{ 1, 2, 3, }); - assert(list.len == 102); - assert(list.pop().? == 3); - assert(list.pop().? == 2); - assert(list.pop().? == 1); - assert(list.len == 99); + testing.expect(list.len == 102); + testing.expect(list.pop().? == 3); + testing.expect(list.pop().? == 2); + testing.expect(list.pop().? == 1); + testing.expect(list.len == 99); try list.pushMany([]const i32{}); - assert(list.len == 99); + testing.expect(list.len == 99); var i: i32 = 99; while (list.pop()) |item| : (i -= 1) { - assert(item == i); + testing.expect(item == i); list.shrinkCapacity(list.len); } } diff --git a/std/sort.zig b/std/sort.zig index f29f51b7cf..86a6724fee 100644 --- a/std/sort.zig +++ b/std/sort.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const math = std.math; const builtin = @import("builtin"); @@ -1031,8 +1032,8 @@ fn testStableSort() void { for (cases) |*case| { insertionSort(IdAndValue, (case.*)[0..], cmpByValue); for (case.*) |item, i| { - assert(item.id == expected[i].id); - assert(item.value == expected[i].value); + testing.expect(item.id == expected[i].id); + testing.expect(item.value == expected[i].value); } } } @@ -1077,7 +1078,7 @@ test "std.sort" { const slice = buf[0..case[0].len]; mem.copy(u8, slice, case[0]); sort(u8, slice, asc(u8)); - assert(mem.eql(u8, slice, case[1])); + testing.expect(mem.eql(u8, slice, case[1])); } const i32cases = [][]const []const i32{ @@ -1112,7 +1113,7 @@ test "std.sort" { const slice = buf[0..case[0].len]; mem.copy(i32, slice, case[0]); sort(i32, slice, asc(i32)); - assert(mem.eql(i32, slice, case[1])); + testing.expect(mem.eql(i32, slice, case[1])); } } @@ -1149,7 +1150,7 @@ test "std.sort descending" { const slice = buf[0..case[0].len]; mem.copy(i32, slice, case[0]); sort(i32, slice, desc(i32)); - assert(mem.eql(i32, slice, case[1])); + testing.expect(mem.eql(i32, slice, case[1])); } } @@ -1157,7 +1158,7 @@ test "another sort case" { var arr = []i32{ 5, 3, 1, 2, 4 }; sort(i32, arr[0..], asc(i32)); - assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 })); + testing.expect(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 })); } test "sort fuzz testing" { @@ -1185,9 +1186,9 @@ fn fuzzTest(rng: *std.rand.Random) void { var index: usize = 1; while (index < array.len) : (index += 1) { if (array[index].value == array[index - 1].value) { - assert(array[index].id > array[index - 1].id); + testing.expect(array[index].id > array[index - 1].id); } else { - assert(array[index].value > array[index - 1].value); + testing.expect(array[index].value > array[index - 1].value); } } } diff --git a/std/special/compiler_rt/divti3_test.zig b/std/special/compiler_rt/divti3_test.zig index eef5a9b812..e1c1babae7 100644 --- a/std/special/compiler_rt/divti3_test.zig +++ b/std/special/compiler_rt/divti3_test.zig @@ -1,9 +1,9 @@ const __divti3 = @import("divti3.zig").__divti3; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__divti3(a: i128, b: i128, expected: i128) void { const x = __divti3(a, b); - assert(x == expected); + testing.expect(x == expected); } test "divti3" { diff --git a/std/special/compiler_rt/extendXfYf2_test.zig b/std/special/compiler_rt/extendXfYf2_test.zig index 9969607011..050a799823 100644 --- a/std/special/compiler_rt/extendXfYf2_test.zig +++ b/std/special/compiler_rt/extendXfYf2_test.zig @@ -1,7 +1,6 @@ const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; -const assert = @import("std").debug.assert; fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void { const x = __extenddftf2(a); diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/std/special/compiler_rt/fixdfdi_test.zig index 72bcf452d2..a55245210b 100644 --- a/std/special/compiler_rt/fixdfdi_test.zig +++ b/std/special/compiler_rt/fixdfdi_test.zig @@ -1,13 +1,13 @@ const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfdi(a: f64, expected: i64) void { const x = __fixdfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfdi" { diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/std/special/compiler_rt/fixdfsi_test.zig index 147f46534a..5cb9bef1d9 100644 --- a/std/special/compiler_rt/fixdfsi_test.zig +++ b/std/special/compiler_rt/fixdfsi_test.zig @@ -1,13 +1,13 @@ const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfsi(a: f64, expected: i32) void { const x = __fixdfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfsi" { diff --git a/std/special/compiler_rt/fixdfti_test.zig b/std/special/compiler_rt/fixdfti_test.zig index 5bb3a31a3f..5fbcd206ed 100644 --- a/std/special/compiler_rt/fixdfti_test.zig +++ b/std/special/compiler_rt/fixdfti_test.zig @@ -1,13 +1,13 @@ const __fixdfti = @import("fixdfti.zig").__fixdfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfti(a: f64, expected: i128) void { const x = __fixdfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfti" { diff --git a/std/special/compiler_rt/fixint_test.zig b/std/special/compiler_rt/fixint_test.zig index 6676bddbee..0b0936d1e2 100644 --- a/std/special/compiler_rt/fixint_test.zig +++ b/std/special/compiler_rt/fixint_test.zig @@ -1,7 +1,7 @@ const is_test = @import("builtin").is_test; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; const fixint = @import("fixint.zig").fixint; @@ -9,7 +9,7 @@ const fixint = @import("fixint.zig").fixint; fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void { const x = fixint(fp_t, fixint_t, a); //warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected); - assert(x == expected); + testing.expect(x == expected); } test "fixint.i1" { diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/std/special/compiler_rt/fixsfdi_test.zig index ef8e50e38e..276670421b 100644 --- a/std/special/compiler_rt/fixsfdi_test.zig +++ b/std/special/compiler_rt/fixsfdi_test.zig @@ -1,13 +1,13 @@ const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfdi(a: f32, expected: i64) void { const x = __fixsfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfdi" { diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/std/special/compiler_rt/fixsfsi_test.zig index d5c0ba5c2a..a05c15e536 100644 --- a/std/special/compiler_rt/fixsfsi_test.zig +++ b/std/special/compiler_rt/fixsfsi_test.zig @@ -1,13 +1,13 @@ const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfsi(a: f32, expected: i32) void { const x = __fixsfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfsi" { diff --git a/std/special/compiler_rt/fixsfti_test.zig b/std/special/compiler_rt/fixsfti_test.zig index d693143b18..32410e2dee 100644 --- a/std/special/compiler_rt/fixsfti_test.zig +++ b/std/special/compiler_rt/fixsfti_test.zig @@ -1,13 +1,13 @@ const __fixsfti = @import("fixsfti.zig").__fixsfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfti(a: f32, expected: i128) void { const x = __fixsfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfti" { diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/std/special/compiler_rt/fixtfdi_test.zig index 58ccbc5832..a31bcb7d6f 100644 --- a/std/special/compiler_rt/fixtfdi_test.zig +++ b/std/special/compiler_rt/fixtfdi_test.zig @@ -1,13 +1,13 @@ const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfdi(a: f128, expected: i64) void { const x = __fixtfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfdi" { diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/std/special/compiler_rt/fixtfsi_test.zig index 7a3cc7f46c..7b37e4e09f 100644 --- a/std/special/compiler_rt/fixtfsi_test.zig +++ b/std/special/compiler_rt/fixtfsi_test.zig @@ -1,13 +1,13 @@ const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfsi(a: f128, expected: i32) void { const x = __fixtfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfsi" { diff --git a/std/special/compiler_rt/fixtfti_test.zig b/std/special/compiler_rt/fixtfti_test.zig index 520009486a..be461a1c91 100644 --- a/std/special/compiler_rt/fixtfti_test.zig +++ b/std/special/compiler_rt/fixtfti_test.zig @@ -1,13 +1,13 @@ const __fixtfti = @import("fixtfti.zig").__fixtfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfti(a: f128, expected: i128) void { const x = __fixtfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfti" { diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/std/special/compiler_rt/fixunsdfdi_test.zig index e59d09f8de..67eeb70520 100644 --- a/std/special/compiler_rt/fixunsdfdi_test.zig +++ b/std/special/compiler_rt/fixunsdfdi_test.zig @@ -1,9 +1,9 @@ const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfdi(a: f64, expected: u64) void { const x = __fixunsdfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfdi" { diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/std/special/compiler_rt/fixunsdfsi_test.zig index db6e32e23d..c006473fb9 100644 --- a/std/special/compiler_rt/fixunsdfsi_test.zig +++ b/std/special/compiler_rt/fixunsdfsi_test.zig @@ -1,9 +1,9 @@ const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfsi(a: f64, expected: u32) void { const x = __fixunsdfsi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfsi" { diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/std/special/compiler_rt/fixunsdfti_test.zig index 7f7b083d19..8241900692 100644 --- a/std/special/compiler_rt/fixunsdfti_test.zig +++ b/std/special/compiler_rt/fixunsdfti_test.zig @@ -1,9 +1,9 @@ const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfti(a: f64, expected: u128) void { const x = __fixunsdfti(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfti" { diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/std/special/compiler_rt/fixunssfdi_test.zig index e4e6c1736d..e2089822d2 100644 --- a/std/special/compiler_rt/fixunssfdi_test.zig +++ b/std/special/compiler_rt/fixunssfdi_test.zig @@ -1,9 +1,9 @@ const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfdi(a: f32, expected: u64) void { const x = __fixunssfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfdi" { diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/std/special/compiler_rt/fixunssfsi_test.zig index 614c648dfe..4aee84d2d2 100644 --- a/std/special/compiler_rt/fixunssfsi_test.zig +++ b/std/special/compiler_rt/fixunssfsi_test.zig @@ -1,9 +1,9 @@ const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfsi(a: f32, expected: u32) void { const x = __fixunssfsi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfsi" { diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/std/special/compiler_rt/fixunssfti_test.zig index 43ad527f53..4cb27cbb8a 100644 --- a/std/special/compiler_rt/fixunssfti_test.zig +++ b/std/special/compiler_rt/fixunssfti_test.zig @@ -1,9 +1,9 @@ const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfti(a: f32, expected: u128) void { const x = __fixunssfti(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfti" { diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig index 6b1b9b7bd2..0d47641c09 100644 --- a/std/special/compiler_rt/fixunstfdi_test.zig +++ b/std/special/compiler_rt/fixunstfdi_test.zig @@ -1,9 +1,9 @@ const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfdi(a: f128, expected: u64) void { const x = __fixunstfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunstfdi" { diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig index f47fcb3c86..e709636912 100644 --- a/std/special/compiler_rt/fixunstfsi_test.zig +++ b/std/special/compiler_rt/fixunstfsi_test.zig @@ -1,9 +1,9 @@ const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfsi(a: f128, expected: u32) void { const x = __fixunstfsi(a); - assert(x == expected); + testing.expect(x == expected); } const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); diff --git a/std/special/compiler_rt/fixunstfti_test.zig b/std/special/compiler_rt/fixunstfti_test.zig index 9128ac6c08..833e4779dd 100644 --- a/std/special/compiler_rt/fixunstfti_test.zig +++ b/std/special/compiler_rt/fixunstfti_test.zig @@ -1,9 +1,9 @@ const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfti(a: f128, expected: u128) void { const x = __fixunstfti(a); - assert(x == expected); + testing.expect(x == expected); } const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); diff --git a/std/special/compiler_rt/floattidf_test.zig b/std/special/compiler_rt/floattidf_test.zig index 25dc595052..4914342c31 100644 --- a/std/special/compiler_rt/floattidf_test.zig +++ b/std/special/compiler_rt/floattidf_test.zig @@ -1,9 +1,9 @@ const __floattidf = @import("floattidf.zig").__floattidf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattidf(a: i128, expected: f64) void { const x = __floattidf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattidf" { diff --git a/std/special/compiler_rt/floattisf_test.zig b/std/special/compiler_rt/floattisf_test.zig index ecb8eac60a..a6aa115307 100644 --- a/std/special/compiler_rt/floattisf_test.zig +++ b/std/special/compiler_rt/floattisf_test.zig @@ -1,9 +1,9 @@ const __floattisf = @import("floattisf.zig").__floattisf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattisf(a: i128, expected: f32) void { const x = __floattisf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattisf" { diff --git a/std/special/compiler_rt/floattitf_test.zig b/std/special/compiler_rt/floattitf_test.zig index da2ccc8b35..53e3e48bdb 100644 --- a/std/special/compiler_rt/floattitf_test.zig +++ b/std/special/compiler_rt/floattitf_test.zig @@ -1,9 +1,9 @@ const __floattitf = @import("floattitf.zig").__floattitf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattitf(a: i128, expected: f128) void { const x = __floattitf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattitf" { diff --git a/std/special/compiler_rt/floatunditf_test.zig b/std/special/compiler_rt/floatunditf_test.zig index 8533c75070..5b4e195870 100644 --- a/std/special/compiler_rt/floatunditf_test.zig +++ b/std/special/compiler_rt/floatunditf_test.zig @@ -1,5 +1,4 @@ const __floatunditf = @import("floatunditf.zig").__floatunditf; -const assert = @import("std").debug.assert; fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void { const x = __floatunditf(a); diff --git a/std/special/compiler_rt/floatunsitf_test.zig b/std/special/compiler_rt/floatunsitf_test.zig index 06f54cde03..52e4786903 100644 --- a/std/special/compiler_rt/floatunsitf_test.zig +++ b/std/special/compiler_rt/floatunsitf_test.zig @@ -1,5 +1,4 @@ const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; -const assert = @import("std").debug.assert; fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void { const x = __floatunsitf(a); diff --git a/std/special/compiler_rt/floatuntidf_test.zig b/std/special/compiler_rt/floatuntidf_test.zig index e2c79378e2..974f3e4be3 100644 --- a/std/special/compiler_rt/floatuntidf_test.zig +++ b/std/special/compiler_rt/floatuntidf_test.zig @@ -1,9 +1,9 @@ const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntidf(a: u128, expected: f64) void { const x = __floatuntidf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntidf" { diff --git a/std/special/compiler_rt/floatuntisf_test.zig b/std/special/compiler_rt/floatuntisf_test.zig index 7f84c1f963..3a97807066 100644 --- a/std/special/compiler_rt/floatuntisf_test.zig +++ b/std/special/compiler_rt/floatuntisf_test.zig @@ -1,9 +1,9 @@ const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntisf(a: u128, expected: f32) void { const x = __floatuntisf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntisf" { diff --git a/std/special/compiler_rt/floatuntitf_test.zig b/std/special/compiler_rt/floatuntitf_test.zig index 8e67fee108..09f3eabb3e 100644 --- a/std/special/compiler_rt/floatuntitf_test.zig +++ b/std/special/compiler_rt/floatuntitf_test.zig @@ -1,9 +1,9 @@ const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntitf(a: u128, expected: f128) void { const x = __floatuntitf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntitf" { diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 4bbfc2b290..3df94db589 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -110,6 +110,7 @@ comptime { const std = @import("std"); const assert = std.debug.assert; +const testing = std.testing; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -417,7 +418,7 @@ test "test_umoddi3" { fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void { const r = __umoddi3(a, b); - assert(r == expected_r); + testing.expect(r == expected_r); } test "test_udivsi3" { @@ -1091,5 +1092,5 @@ test "test_udivsi3" { fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void { const q: u32 = __udivsi3(a, b); - assert(q == expected_q); + testing.expect(q == expected_q); } diff --git a/std/special/compiler_rt/muloti4_test.zig b/std/special/compiler_rt/muloti4_test.zig index 6b3671323f..00144a8839 100644 --- a/std/special/compiler_rt/muloti4_test.zig +++ b/std/special/compiler_rt/muloti4_test.zig @@ -1,10 +1,10 @@ const __muloti4 = @import("muloti4.zig").__muloti4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) void { var overflow: c_int = undefined; const x = __muloti4(a, b, &overflow); - assert(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); + testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); } test "muloti4" { diff --git a/std/special/compiler_rt/multi3_test.zig b/std/special/compiler_rt/multi3_test.zig index 413ff20a79..92c580e20f 100644 --- a/std/special/compiler_rt/multi3_test.zig +++ b/std/special/compiler_rt/multi3_test.zig @@ -1,9 +1,9 @@ const __multi3 = @import("multi3.zig").__multi3; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__multi3(a: i128, b: i128, expected: i128) void { const x = __multi3(a, b); - assert(x == expected); + testing.expect(x == expected); } test "multi3" { diff --git a/std/special/compiler_rt/udivmoddi4_test.zig b/std/special/compiler_rt/udivmoddi4_test.zig index 34b9dda1ea..5e6924f290 100644 --- a/std/special/compiler_rt/udivmoddi4_test.zig +++ b/std/special/compiler_rt/udivmoddi4_test.zig @@ -1,13 +1,13 @@ // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__udivmoddi4(a: u64, b: u64, expected_q: u64, expected_r: u64) void { var r: u64 = undefined; const q = __udivmoddi4(a, b, &r); - assert(q == expected_q); - assert(r == expected_r); + testing.expect(q == expected_q); + testing.expect(r == expected_r); } test "udivmoddi4" { diff --git a/std/special/compiler_rt/udivmodti4_test.zig b/std/special/compiler_rt/udivmodti4_test.zig index f6b370c26e..0c7880f346 100644 --- a/std/special/compiler_rt/udivmodti4_test.zig +++ b/std/special/compiler_rt/udivmodti4_test.zig @@ -1,13 +1,13 @@ // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__udivmodti4(a: u128, b: u128, expected_q: u128, expected_r: u128) void { var r: u128 = undefined; const q = __udivmodti4(a, b, &r); - assert(q == expected_q); - assert(r == expected_r); + testing.expect(q == expected_q); + testing.expect(r == expected_r); } test "udivmodti4" { diff --git a/std/special/init-lib/src/main.zig b/std/special/init-lib/src/main.zig index 27fdeb2030..747bb08573 100644 --- a/std/special/init-lib/src/main.zig +++ b/std/special/init-lib/src/main.zig @@ -1,10 +1,10 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; export fn add(a: i32, b: i32) i32 { return a + b; } test "basic add functionality" { - assertOrPanic(add(3, 7) == 10); + testing.expect(add(3, 7) == 10); } diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig index 37582d49c1..16bcd7adaf 100644 --- a/std/statically_initialized_mutex.zig +++ b/std/statically_initialized_mutex.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; const assert = std.debug.assert; +const expect = std.testing.expect; const windows = std.os.windows; /// Lock may be held only once. If the same thread @@ -95,7 +96,7 @@ test "std.StaticallyInitializedMutex" { if (builtin.single_threaded) { TestContext.worker(&context); - std.debug.assertOrPanic(context.data == TestContext.incr_count); + expect(context.data == TestContext.incr_count); } else { const thread_count = 10; var threads: [thread_count]*std.os.Thread = undefined; @@ -105,6 +106,6 @@ test "std.StaticallyInitializedMutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + expect(context.data == thread_count * TestContext.incr_count); } } diff --git a/std/testing.zig b/std/testing.zig new file mode 100644 index 0000000000..ade6e8b0dd --- /dev/null +++ b/std/testing.zig @@ -0,0 +1,152 @@ +const builtin = @import("builtin"); +const TypeId = builtin.TypeId; +const std = @import("index.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. +pub fn expectError(expected_error: anyerror, actual_error_union: var) void { + // TODO remove the workaround here for https://github.com/ziglang/zig/issues/1936 + if (actual_error_union) |actual_payload| { + // TODO remove workaround here for https://github.com/ziglang/zig/issues/557 + if (@sizeOf(@typeOf(actual_payload)) == 0) { + std.debug.panic("expected error.{}, found {} value", @errorName(expected_error), @typeName(@typeOf(actual_payload))); + } else { + std.debug.panic("expected error.{}, found {}", @errorName(expected_error), actual_payload); + } + } else |actual_error| { + if (expected_error != actual_error) { + std.debug.panic("expected error.{}, found error.{}", @errorName(expected_error), @errorName(actual_error)); + } + } +} + +/// This function is intended to be used only in tests. When the two values are not +/// equal, prints diagnostics to stderr to show exactly how they are not equal, +/// then aborts. +/// The types must match exactly. +pub fn expectEqual(expected: var, actual: var) void { + if (@typeOf(actual) != @typeOf(expected)) { + @compileError("type mismatch. expected " ++ @typeName(@typeOf(expected)) ++ ", found " ++ @typeName(@typeOf(actual))); + } + + switch (@typeInfo(@typeOf(actual))) { + TypeId.NoReturn, + TypeId.BoundFn, + TypeId.ArgTuple, + TypeId.Opaque, + => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"), + + TypeId.Undefined, + TypeId.Null, + TypeId.Void, + => return, + + TypeId.Type, + TypeId.Bool, + TypeId.Int, + TypeId.Float, + TypeId.ComptimeFloat, + TypeId.ComptimeInt, + TypeId.Enum, + TypeId.Namespace, + TypeId.Fn, + TypeId.Promise, + TypeId.Vector, + TypeId.ErrorSet, + => { + if (actual != expected) { + std.debug.panic("expected {}, found {}", expected, actual); + } + }, + + TypeId.Pointer => |pointer| { + switch (pointer.size) { + builtin.TypeInfo.Pointer.Size.One, + builtin.TypeInfo.Pointer.Size.Many, + => { + if (actual != expected) { + std.debug.panic("expected {}, found {}", expected, actual); + } + }, + + builtin.TypeInfo.Pointer.Size.Slice => { + if (actual.ptr != expected.ptr) { + std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr); + } + if (actual.len != expected.len) { + std.debug.panic("expected slice len {}, found {}", expected.len, actual.len); + } + }, + } + }, + + TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual), + + TypeId.Struct => { + @compileError("TODO implement testing.expectEqual for structs"); + }, + + TypeId.Union => |union_info| { + if (union_info.tag_type == null) { + @compileError("Unable to compare untagged union values"); + } + @compileError("TODO implement testing.expectEqual for tagged unions"); + }, + + TypeId.Optional => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + expectEqual(expected_payload, actual_payload); + } else { + std.debug.panic("expected {}, found null", expected_payload); + } + } else { + if (actual) |actual_payload| { + std.debug.panic("expected null, found {}", actual_payload); + } + } + }, + + TypeId.ErrorUnion => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + expectEqual(expected_payload, actual_payload); + } else |actual_err| { + std.debug.panic("expected {}, found {}", expected_payload, actual_err); + } + } else |expected_err| { + if (actual) |actual_payload| { + std.debug.panic("expected {}, found {}", expected_err, actual_payload); + } else |actual_err| { + expectEqual(expected_err, actual_err); + } + } + }, + + } +} + +/// This function is intended to be used only in tests. When the two slices are not +/// equal, prints diagnostics to stderr to show exactly how they are not equal, +/// then aborts. +pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) void { + // TODO better printing of the difference + // If the arrays are small enough we could print the whole thing + // If the child type is u8 and no weird bytes, we could print it as strings + // Even for the length difference, it would be useful to see the values of the slices probably. + if (expected.len != actual.len) { + std.debug.panic("slice lengths differ. expected {}, found {}", expected.len, actual.len); + } + var i: usize = 0; + while (i < expected.len) : (i += 1) { + if (expected[i] != actual[i]) { + std.debug.panic("index {} incorrect. expected {}, found {}", i, expected[i], actual[i]); + } + } +} + +/// This function is intended to be used only in tests. When `ok` is false, the test fails. +/// A message is printed to stderr and then abort is called. +pub fn expect(ok: bool) void { + if (!ok) @panic("test failure"); +} diff --git a/std/unicode.zig b/std/unicode.zig index 2e542bcb19..fccdf513b9 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -1,7 +1,7 @@ const std = @import("./index.zig"); const builtin = @import("builtin"); -const debug = std.debug; const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; /// Returns how many bytes the UTF-8 representation would require @@ -32,7 +32,7 @@ pub fn utf8ByteSequenceLength(first_byte: u8) !u3 { /// Returns: the number of bytes written to out. pub fn utf8Encode(c: u32, out: []u8) !u3 { const length = try utf8CodepointSequenceLength(c); - debug.assert(out.len >= length); + assert(out.len >= length); switch (length) { // The pattern for each is the same // - Increasing the initial shift by 6 each time @@ -81,8 +81,8 @@ const Utf8Decode2Error = error{ Utf8OverlongEncoding, }; pub fn utf8Decode2(bytes: []const u8) Utf8Decode2Error!u32 { - debug.assert(bytes.len == 2); - debug.assert(bytes[0] & 0b11100000 == 0b11000000); + assert(bytes.len == 2); + assert(bytes[0] & 0b11100000 == 0b11000000); var value: u32 = bytes[0] & 0b00011111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -100,8 +100,8 @@ const Utf8Decode3Error = error{ Utf8EncodesSurrogateHalf, }; pub fn utf8Decode3(bytes: []const u8) Utf8Decode3Error!u32 { - debug.assert(bytes.len == 3); - debug.assert(bytes[0] & 0b11110000 == 0b11100000); + assert(bytes.len == 3); + assert(bytes[0] & 0b11110000 == 0b11100000); var value: u32 = bytes[0] & 0b00001111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -124,8 +124,8 @@ const Utf8Decode4Error = error{ Utf8CodepointTooLarge, }; pub fn utf8Decode4(bytes: []const u8) Utf8Decode4Error!u32 { - debug.assert(bytes.len == 4); - debug.assert(bytes[0] & 0b11111000 == 0b11110000); + assert(bytes.len == 4); + assert(bytes[0] & 0b11111000 == 0b11110000); var value: u32 = bytes[0] & 0b00000111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -274,23 +274,23 @@ test "utf8 encode" { fn testUtf8Encode() !void { // A few taken from wikipedia a few taken elsewhere var array: [4]u8 = undefined; - debug.assert((try utf8Encode(try utf8Decode("€"), array[0..])) == 3); - debug.assert(array[0] == 0b11100010); - debug.assert(array[1] == 0b10000010); - debug.assert(array[2] == 0b10101100); + testing.expect((try utf8Encode(try utf8Decode("€"), array[0..])) == 3); + testing.expect(array[0] == 0b11100010); + testing.expect(array[1] == 0b10000010); + testing.expect(array[2] == 0b10101100); - debug.assert((try utf8Encode(try utf8Decode("$"), array[0..])) == 1); - debug.assert(array[0] == 0b00100100); + testing.expect((try utf8Encode(try utf8Decode("$"), array[0..])) == 1); + testing.expect(array[0] == 0b00100100); - debug.assert((try utf8Encode(try utf8Decode("¢"), array[0..])) == 2); - debug.assert(array[0] == 0b11000010); - debug.assert(array[1] == 0b10100010); + testing.expect((try utf8Encode(try utf8Decode("¢"), array[0..])) == 2); + testing.expect(array[0] == 0b11000010); + testing.expect(array[1] == 0b10100010); - debug.assert((try utf8Encode(try utf8Decode("𐍈"), array[0..])) == 4); - debug.assert(array[0] == 0b11110000); - debug.assert(array[1] == 0b10010000); - debug.assert(array[2] == 0b10001101); - debug.assert(array[3] == 0b10001000); + testing.expect((try utf8Encode(try utf8Decode("𐍈"), array[0..])) == 4); + testing.expect(array[0] == 0b11110000); + testing.expect(array[1] == 0b10010000); + testing.expect(array[2] == 0b10001101); + testing.expect(array[3] == 0b10001000); } test "utf8 encode error" { @@ -306,11 +306,7 @@ fn testUtf8EncodeError() void { } fn testErrorEncode(codePoint: u32, array: []u8, expectedErr: anyerror) void { - if (utf8Encode(codePoint, array)) |_| { - unreachable; - } else |err| { - debug.assert(err == expectedErr); - } + testing.expectError(expectedErr, utf8Encode(codePoint, array)); } test "utf8 iterator on ascii" { @@ -321,16 +317,16 @@ fn testUtf8IteratorOnAscii() void { const s = Utf8View.initComptime("abc"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?)); - debug.assert(it1.nextCodepointSlice() == null); + testing.expect(std.mem.eql(u8, "a", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "b", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "c", it1.nextCodepointSlice().?)); + testing.expect(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(it2.nextCodepoint().? == 'a'); - debug.assert(it2.nextCodepoint().? == 'b'); - debug.assert(it2.nextCodepoint().? == 'c'); - debug.assert(it2.nextCodepoint() == null); + testing.expect(it2.nextCodepoint().? == 'a'); + testing.expect(it2.nextCodepoint().? == 'b'); + testing.expect(it2.nextCodepoint().? == 'c'); + testing.expect(it2.nextCodepoint() == null); } test "utf8 view bad" { @@ -340,12 +336,7 @@ test "utf8 view bad" { fn testUtf8ViewBad() void { // Compile-time error. // const s3 = Utf8View.initComptime("\xfe\xf2"); - const s = Utf8View.init("hel\xadlo"); - if (s) |_| { - unreachable; - } else |err| { - debug.assert(err == error.InvalidUtf8); - } + testing.expectError(error.InvalidUtf8, Utf8View.init("hel\xadlo")); } test "utf8 view ok" { @@ -356,16 +347,16 @@ fn testUtf8ViewOk() void { const s = Utf8View.initComptime("東京市"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?)); - debug.assert(it1.nextCodepointSlice() == null); + testing.expect(std.mem.eql(u8, "東", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "京", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "市", it1.nextCodepointSlice().?)); + testing.expect(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(it2.nextCodepoint().? == 0x6771); - debug.assert(it2.nextCodepoint().? == 0x4eac); - debug.assert(it2.nextCodepoint().? == 0x5e02); - debug.assert(it2.nextCodepoint() == null); + testing.expect(it2.nextCodepoint().? == 0x6771); + testing.expect(it2.nextCodepoint().? == 0x4eac); + testing.expect(it2.nextCodepoint().? == 0x5e02); + testing.expect(it2.nextCodepoint() == null); } test "bad utf8 slice" { @@ -373,10 +364,10 @@ test "bad utf8 slice" { testBadUtf8Slice(); } fn testBadUtf8Slice() void { - debug.assert(utf8ValidateSlice("abc")); - debug.assert(!utf8ValidateSlice("abc\xc0")); - debug.assert(!utf8ValidateSlice("abc\xc0abc")); - debug.assert(utf8ValidateSlice("abc\xdf\xbf")); + testing.expect(utf8ValidateSlice("abc")); + testing.expect(!utf8ValidateSlice("abc\xc0")); + testing.expect(!utf8ValidateSlice("abc\xc0abc")); + testing.expect(utf8ValidateSlice("abc\xdf\xbf")); } test "valid utf8" { @@ -459,21 +450,17 @@ fn testMiscInvalidUtf8() void { } fn testError(bytes: []const u8, expected_err: anyerror) void { - if (testDecode(bytes)) |_| { - unreachable; - } else |err| { - debug.assert(err == expected_err); - } + testing.expectError(expected_err, testDecode(bytes)); } fn testValid(bytes: []const u8, expected_codepoint: u32) void { - debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint); + testing.expect((testDecode(bytes) catch unreachable) == expected_codepoint); } fn testDecode(bytes: []const u8) !u32 { const length = try utf8ByteSequenceLength(bytes[0]); if (bytes.len < length) return error.UnexpectedEof; - debug.assert(bytes.len == length); + testing.expect(bytes.len == length); return utf8Decode(bytes); } @@ -513,14 +500,14 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "Aa")); + testing.expect(mem.eql(u8, utf8, "Aa")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); + testing.expect(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { @@ -528,7 +515,7 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); + testing.expect(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { @@ -536,7 +523,7 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); + testing.expect(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { @@ -544,14 +531,14 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); + testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); + testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } } diff --git a/std/zig/ast.zig b/std/zig/ast.zig index bb2099fb75..f6ac4ed98c 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -1,5 +1,6 @@ const std = @import("../index.zig"); const assert = std.debug.assert; +const testing = std.testing; const SegmentedList = std.SegmentedList; const mem = std.mem; const Token = std.zig.Token; @@ -2224,5 +2225,5 @@ test "iterate" { .shebang = null, }; var base = &root.base; - assert(base.iterate(0) == null); + testing.expect(base.iterate(0) == null); } diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 2b60fb9b00..7ad842e4b6 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1940,7 +1940,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { warn("std.zig.render returned {} instead of {}\n", anything_changed, changes_expected); return error.TestFailed; } - std.debug.assert(anything_changed == changes_expected); + std.testing.expect(anything_changed == changes_expected); failing_allocator.allocator.free(result_source); break :x failing_allocator.index; }; diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 4941fe2cc2..e71babe4e8 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -1345,5 +1345,5 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { } } const last_token = tokenizer.next(); - std.debug.assert(last_token.id == Token.Id.Eof); + std.testing.expect(last_token.id == Token.Id.Eof); } diff --git a/test/cli.zig b/test/cli.zig index 745da4dd80..1520b3bde0 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -1,7 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const os = std.os; -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; var a: *std.mem.Allocator = undefined; @@ -87,13 +87,13 @@ fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult { fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void { _ = try exec(dir_path, [][]const u8{ zig_exe, "init-lib" }); const test_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "test" }); - assertOrPanic(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); + testing.expect(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); } fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { _ = try exec(dir_path, [][]const u8{ zig_exe, "init-exe" }); const run_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "run" }); - assertOrPanic(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); + testing.expect(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); } fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { @@ -126,6 +126,6 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { _ = try exec(dir_path, args); const out_asm = try std.io.readFileAlloc(a, example_s_path); - assertOrPanic(std.mem.indexOf(u8, out_asm, "square:") != null); - assertOrPanic(std.mem.indexOf(u8, out_asm, "imul\tedi, edi") != null); + testing.expect(std.mem.indexOf(u8, out_asm, "square:") != null); + testing.expect(std.mem.indexOf(u8, out_asm, "imul\tedi, edi") != null); } diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index aa7a93ad84..dbd705ddc4 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -1,13 +1,13 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const builtin = @import("builtin"); var foo: u8 align(4) = 100; test "global variable alignment" { - assertOrPanic(@typeOf(&foo).alignment == 4); - assertOrPanic(@typeOf(&foo) == *align(4) u8); + expect(@typeOf(&foo).alignment == 4); + expect(@typeOf(&foo) == *align(4) u8); const slice = (*[1]u8)(&foo)[0..]; - assertOrPanic(@typeOf(slice) == []align(4) u8); + expect(@typeOf(slice) == []align(4) u8); } fn derp() align(@sizeOf(usize) * 2) i32 { @@ -17,9 +17,9 @@ fn noop1() align(1) void {} fn noop4() align(4) void {} test "function alignment" { - assertOrPanic(derp() == 1234); - assertOrPanic(@typeOf(noop1) == fn () align(1) void); - assertOrPanic(@typeOf(noop4) == fn () align(4) void); + expect(derp() == 1234); + expect(@typeOf(noop1) == fn () align(1) void); + expect(@typeOf(noop4) == fn () align(4) void); noop1(); noop4(); } @@ -30,7 +30,7 @@ var baz: packed struct { } = undefined; test "packed struct alignment" { - assertOrPanic(@typeOf(&baz.b) == *align(1) u32); + expect(@typeOf(&baz.b) == *align(1) u32); } const blah: packed struct { @@ -40,17 +40,17 @@ const blah: packed struct { } = undefined; test "bit field alignment" { - assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3); + expect(@typeOf(&blah.b) == *align(1:3:1) const u3); } test "default alignment allows unspecified in type syntax" { - assertOrPanic(*u32 == *align(@alignOf(u32)) u32); + expect(*u32 == *align(@alignOf(u32)) u32); } test "implicitly decreasing pointer alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assertOrPanic(addUnaligned(&a, &b) == 7); + expect(addUnaligned(&a, &b) == 7); } fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { @@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { test "implicitly decreasing slice alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); + expect(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); } fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; @@ -77,7 +77,7 @@ fn testBytesAlign(b: u8) void { b, }; const ptr = @ptrCast(*u32, &bytes[0]); - assertOrPanic(ptr.* == 0x33333333); + expect(ptr.* == 0x33333333); } test "specifying alignment allows slice cast" { @@ -91,13 +91,13 @@ fn testBytesAlignSlice(b: u8) void { b, }; const slice: []u32 = @bytesToSlice(u32, bytes[0..]); - assertOrPanic(slice[0] == 0x33333333); + expect(slice[0] == 0x33333333); } test "@alignCast pointers" { var x: u32 align(4) = 1; expectsOnly1(&x); - assertOrPanic(x == 2); + expect(x == 2); } fn expectsOnly1(x: *align(1) u32) void { expects4(@alignCast(4, x)); @@ -113,7 +113,7 @@ test "@alignCast slices" { }; const slice = array[0..]; sliceExpectsOnly1(slice); - assertOrPanic(slice[0] == 2); + expect(slice[0] == 2); } fn sliceExpectsOnly1(slice: []align(1) u32) void { sliceExpects4(@alignCast(4, slice)); @@ -128,7 +128,7 @@ test "implicitly decreasing fn alignment" { } fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { - assertOrPanic(ptr() == answer); + expect(ptr() == answer); } fn alignedSmall() align(8) i32 { @@ -139,7 +139,7 @@ fn alignedBig() align(16) i32 { } test "@alignCast functions" { - assertOrPanic(fnExpectsOnly1(simple4) == 0x19); + expect(fnExpectsOnly1(simple4) == 0x19); } fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { return fnExpects4(@alignCast(4, ptr)); @@ -152,9 +152,9 @@ fn simple4() align(4) i32 { } test "generic function with align param" { - assertOrPanic(whyWouldYouEverDoThis(1) == 0x1); - assertOrPanic(whyWouldYouEverDoThis(4) == 0x1); - assertOrPanic(whyWouldYouEverDoThis(8) == 0x1); + expect(whyWouldYouEverDoThis(1) == 0x1); + expect(whyWouldYouEverDoThis(4) == 0x1); + expect(whyWouldYouEverDoThis(8) == 0x1); } fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { @@ -164,28 +164,28 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { test "@ptrCast preserves alignment of bigger source" { var x: u32 align(16) = 1234; const ptr = @ptrCast(*u8, &x); - assertOrPanic(@typeOf(ptr) == *align(16) u8); + expect(@typeOf(ptr) == *align(16) u8); } test "runtime known array index has best alignment possible" { // take full advantage of over-alignment var array align(4) = []u8{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(&array[0]) == *align(4) u8); - assertOrPanic(@typeOf(&array[1]) == *u8); - assertOrPanic(@typeOf(&array[2]) == *align(2) u8); - assertOrPanic(@typeOf(&array[3]) == *u8); + expect(@typeOf(&array[0]) == *align(4) u8); + expect(@typeOf(&array[1]) == *u8); + expect(@typeOf(&array[2]) == *align(2) u8); + expect(@typeOf(&array[3]) == *u8); // because align is too small but we still figure out to use 2 var bigger align(2) = []u64{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64); + expect(@typeOf(&bigger[0]) == *align(2) u64); + expect(@typeOf(&bigger[1]) == *align(2) u64); + expect(@typeOf(&bigger[2]) == *align(2) u64); + expect(@typeOf(&bigger[3]) == *align(2) u64); // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 var smaller align(2) = []u32{ 1, 2, 3, 4 }; - comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32); - comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32); + comptime expect(@typeOf(smaller[0..]) == []align(2) u32); + comptime expect(@typeOf(smaller[0..].ptr) == [*]align(2) u32); testIndex(smaller[0..].ptr, 0, *align(2) u32); testIndex(smaller[0..].ptr, 1, *align(2) u32); testIndex(smaller[0..].ptr, 2, *align(2) u32); @@ -198,14 +198,14 @@ test "runtime known array index has best alignment possible" { testIndex2(array[0..].ptr, 3, *u8); } fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { - comptime assertOrPanic(@typeOf(&smaller[index]) == T); + comptime expect(@typeOf(&smaller[index]) == T); } fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { - comptime assertOrPanic(@typeOf(&ptr[index]) == T); + comptime expect(@typeOf(&ptr[index]) == T); } test "alignstack" { - assertOrPanic(fnWithAlignedStack() == 1234); + expect(fnWithAlignedStack() == 1234); } fn fnWithAlignedStack() i32 { @@ -214,7 +214,7 @@ fn fnWithAlignedStack() i32 { } test "alignment of structs" { - assertOrPanic(@alignOf(struct { + expect(@alignOf(struct { a: i32, b: *i32, }) == @alignOf(usize)); diff --git a/test/stage1/behavior/alignof.zig b/test/stage1/behavior/alignof.zig index 98c805908b..d4d9661ead 100644 --- a/test/stage1/behavior/alignof.zig +++ b/test/stage1/behavior/alignof.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -10,9 +10,9 @@ const Foo = struct { }; test "@alignOf(T) before referencing T" { - comptime assertOrPanic(@alignOf(Foo) != maxInt(usize)); + comptime expect(@alignOf(Foo) != maxInt(usize)); if (builtin.arch == builtin.Arch.x86_64) { - comptime assertOrPanic(@alignOf(Foo) == 4); + comptime expect(@alignOf(Foo) == 4); } } diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 1183305209..99b828e53c 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; test "arrays" { @@ -18,8 +18,8 @@ test "arrays" { i += 1; } - assertOrPanic(accumulator == 15); - assertOrPanic(getArrayLen(array) == 5); + expect(accumulator == 15); + expect(getArrayLen(array) == 5); } fn getArrayLen(a: []const u32) usize { return a.len; @@ -29,8 +29,8 @@ test "void arrays" { var array: [4]void = undefined; array[0] = void{}; array[1] = array[2]; - assertOrPanic(@sizeOf(@typeOf(array)) == 0); - assertOrPanic(array.len == 4); + expect(@sizeOf(@typeOf(array)) == 0); + expect(array.len == 4); } test "array literal" { @@ -41,12 +41,12 @@ test "array literal" { 1, }; - assertOrPanic(hex_mult.len == 4); - assertOrPanic(hex_mult[1] == 256); + expect(hex_mult.len == 4); + expect(hex_mult[1] == 256); } test "array dot len const expr" { - assertOrPanic(comptime x: { + expect(comptime x: { break :x some_array.len == 4; }); } @@ -70,11 +70,11 @@ test "nested arrays" { "thing", }; for (array_of_strings) |s, i| { - if (i == 0) assertOrPanic(mem.eql(u8, s, "hello")); - if (i == 1) assertOrPanic(mem.eql(u8, s, "this")); - if (i == 2) assertOrPanic(mem.eql(u8, s, "is")); - if (i == 3) assertOrPanic(mem.eql(u8, s, "my")); - if (i == 4) assertOrPanic(mem.eql(u8, s, "thing")); + if (i == 0) expect(mem.eql(u8, s, "hello")); + if (i == 1) expect(mem.eql(u8, s, "this")); + if (i == 2) expect(mem.eql(u8, s, "is")); + if (i == 3) expect(mem.eql(u8, s, "my")); + if (i == 4) expect(mem.eql(u8, s, "thing")); } } @@ -92,9 +92,9 @@ test "set global var array via slice embedded in struct" { s.a[1].b = 2; s.a[2].b = 3; - assertOrPanic(s_array[0].b == 1); - assertOrPanic(s_array[1].b == 2); - assertOrPanic(s_array[2].b == 3); + expect(s_array[0].b == 1); + expect(s_array[1].b == 2); + expect(s_array[2].b == 3); } test "array literal with specified size" { @@ -102,27 +102,27 @@ test "array literal with specified size" { 1, 2, }; - assertOrPanic(array[0] == 1); - assertOrPanic(array[1] == 2); + expect(array[0] == 1); + expect(array[1] == 2); } test "array child property" { var x: [5]i32 = undefined; - assertOrPanic(@typeOf(x).Child == i32); + expect(@typeOf(x).Child == i32); } test "array len property" { var x: [5]i32 = undefined; - assertOrPanic(@typeOf(x).len == 5); + expect(@typeOf(x).len == 5); } test "array len field" { var arr = [4]u8{ 0, 0, 0, 0 }; var ptr = &arr; - assertOrPanic(arr.len == 4); - comptime assertOrPanic(arr.len == 4); - assertOrPanic(ptr.len == 4); - comptime assertOrPanic(ptr.len == 4); + expect(arr.len == 4); + comptime expect(arr.len == 4); + expect(ptr.len == 4); + comptime expect(ptr.len == 4); } test "single-item pointer to array indexing and slicing" { @@ -133,7 +133,7 @@ test "single-item pointer to array indexing and slicing" { fn testSingleItemPtrArrayIndexSlice() void { var array = "aaaa"; doSomeMangling(&array); - assertOrPanic(mem.eql(u8, "azya", array)); + expect(mem.eql(u8, "azya", array)); } fn doSomeMangling(array: *[4]u8) void { @@ -150,7 +150,7 @@ fn testImplicitCastSingleItemPtr() void { var byte: u8 = 100; const slice = (*[1]u8)(&byte)[0..]; slice[0] += 1; - assertOrPanic(byte == 101); + expect(byte == 101); } fn testArrayByValAtComptime(b: [2]u8) u8 { @@ -165,7 +165,7 @@ test "comptime evalutating function that takes array by value" { test "implicit comptime in array type size" { var arr: [plusOne(10)]bool = undefined; - assertOrPanic(arr.len == 11); + expect(arr.len == 11); } fn plusOne(x: u32) u32 { @@ -197,15 +197,15 @@ test "array literal as argument to function" { }); } fn foo(x: []const i32) void { - assertOrPanic(x[0] == 1); - assertOrPanic(x[1] == 2); - assertOrPanic(x[2] == 3); + expect(x[0] == 1); + expect(x[1] == 2); + expect(x[2] == 3); } fn foo2(trash: bool, x: []const i32) void { - assertOrPanic(trash); - assertOrPanic(x[0] == 1); - assertOrPanic(x[1] == 2); - assertOrPanic(x[2] == 3); + expect(trash); + expect(x[0] == 1); + expect(x[1] == 2); + expect(x[2] == 3); } }; S.entry(2); @@ -229,12 +229,12 @@ test "double nested array to const slice cast in array literal" { []i32{1}, []i32{ two, 3 }, }; - assertOrPanic(cases2.len == 2); - assertOrPanic(cases2[0].len == 1); - assertOrPanic(cases2[0][0] == 1); - assertOrPanic(cases2[1].len == 2); - assertOrPanic(cases2[1][0] == 2); - assertOrPanic(cases2[1][1] == 3); + expect(cases2.len == 2); + expect(cases2[0].len == 1); + expect(cases2[0][0] == 1); + expect(cases2[1].len == 2); + expect(cases2[1][0] == 2); + expect(cases2[1][1] == 3); const cases3 = [][]const []const i32{ [][]const i32{[]i32{1}}, @@ -248,21 +248,21 @@ test "double nested array to const slice cast in array literal" { } fn check(cases: []const []const []const i32) void { - assertOrPanic(cases.len == 3); - assertOrPanic(cases[0].len == 1); - assertOrPanic(cases[0][0].len == 1); - assertOrPanic(cases[0][0][0] == 1); - assertOrPanic(cases[1].len == 1); - assertOrPanic(cases[1][0].len == 2); - assertOrPanic(cases[1][0][0] == 2); - assertOrPanic(cases[1][0][1] == 3); - assertOrPanic(cases[2].len == 2); - assertOrPanic(cases[2][0].len == 1); - assertOrPanic(cases[2][0][0] == 4); - assertOrPanic(cases[2][1].len == 3); - assertOrPanic(cases[2][1][0] == 5); - assertOrPanic(cases[2][1][1] == 6); - assertOrPanic(cases[2][1][2] == 7); + expect(cases.len == 3); + expect(cases[0].len == 1); + expect(cases[0][0].len == 1); + expect(cases[0][0][0] == 1); + expect(cases[1].len == 1); + expect(cases[1][0].len == 2); + expect(cases[1][0][0] == 2); + expect(cases[1][0][1] == 3); + expect(cases[2].len == 2); + expect(cases[2][0].len == 1); + expect(cases[2][0][0] == 4); + expect(cases[2][1].len == 3); + expect(cases[2][1][0] == 5); + expect(cases[2][1][1] == 6); + expect(cases[2][1][2] == 7); } }; S.entry(2); diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig index 48701c5836..845d80777a 100644 --- a/test/stage1/behavior/asm.zig +++ b/test/stage1/behavior/asm.zig @@ -1,5 +1,5 @@ const config = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; comptime { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { @@ -13,7 +13,7 @@ comptime { test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assertOrPanic(aoeu() == 1234); + expect(aoeu() == 1234); } } diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig index fa3c5f29a6..daa463fd45 100644 --- a/test/stage1/behavior/atomics.zig +++ b/test/stage1/behavior/atomics.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -7,18 +7,18 @@ const AtomicOrder = builtin.AtomicOrder; test "cmpxchg" { var x: i32 = 1234; if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == 1234); + expect(x1 == 1234); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == 1234); + expect(x1 == 1234); } - assertOrPanic(x == 5678); + expect(x == 5678); - assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assertOrPanic(x == 42); + expect(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + expect(x == 42); } test "fence" { @@ -30,24 +30,24 @@ test "fence" { test "atomicrmw and atomicload" { var data: u8 = 200; testAtomicRmw(&data); - assertOrPanic(data == 42); + expect(data == 42); testAtomicLoad(&data); } fn testAtomicRmw(ptr: *u8) void { const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); - assertOrPanic(prev_value == 200); + expect(prev_value == 200); comptime { var x: i32 = 1234; const y: i32 = 12345; - assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); - assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); + expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); + expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); } } fn testAtomicLoad(ptr: *u8) void { const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); - assertOrPanic(x == 42); + expect(x == 42); } test "cmpxchg with ptr" { @@ -56,16 +56,16 @@ test "cmpxchg with ptr" { var data3: i32 = 9101; var x: *i32 = &data1; if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == &data1); + expect(x1 == &data1); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == &data1); + expect(x1 == &data1); } - assertOrPanic(x == &data3); + expect(x == &data3); - assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assertOrPanic(x == &data2); + expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + expect(x == &data2); } diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig index 3290688358..610acc06c2 100644 --- a/test/stage1/behavior/bit_shifting.zig +++ b/test/stage1/behavior/bit_shifting.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { - assertOrPanic(Key == @IntType(false, Key.bit_count)); - assertOrPanic(Key.bit_count >= mask_bit_count); + expect(Key == @IntType(false, Key.bit_count)); + expect(Key.bit_count >= mask_bit_count); const ShardKey = @IntType(false, mask_bit_count); const shift_amount = Key.bit_count - ShardKey.bit_count; return struct { @@ -77,12 +77,12 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c var node_buffer: [node_count]Table.Node = undefined; for (node_buffer) |*node, i| { const key = @intCast(Key, i); - assertOrPanic(table.get(key) == null); + expect(table.get(key) == null); node.init(key, {}); table.put(node); } for (node_buffer) |*node, i| { - assertOrPanic(table.get(@intCast(Key, i)) == node); + expect(table.get(@intCast(Key, i)) == node); } } diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index 19030255e4..9607d2e3ef 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const maxInt = std.math.maxInt; test "@bitCast i32 -> u32" { @@ -8,8 +8,8 @@ test "@bitCast i32 -> u32" { } fn testBitCast_i32_u32() void { - assertOrPanic(conv(-1) == maxInt(u32)); - assertOrPanic(conv2(maxInt(u32)) == -1); + expect(conv(-1) == maxInt(u32)); + expect(conv2(maxInt(u32)) == -1); } fn conv(x: i32) u32 { @@ -27,7 +27,7 @@ test "@bitCast extern enum to its integer type" { fn testBitCastExternEnum() void { var SOCK_DGRAM = @This().B; var sock_dgram = @bitCast(c_int, SOCK_DGRAM); - assertOrPanic(sock_dgram == 1); + expect(sock_dgram == 1); } }; diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig index 97787ace84..3897a3eab7 100644 --- a/test/stage1/behavior/bitreverse.zig +++ b/test/stage1/behavior/bitreverse.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const minInt = std.math.minInt; test "@bitreverse" { @@ -9,73 +9,73 @@ test "@bitreverse" { fn testBitReverse() void { // using comptime_ints, unsigned - assertOrPanic(@bitreverse(u0, 0) == 0); - assertOrPanic(@bitreverse(u5, 0x12) == 0x9); - assertOrPanic(@bitreverse(u8, 0x12) == 0x48); - assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48); - assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48); - assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); - assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); - assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); - assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); - assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); - assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + expect(@bitreverse(u0, 0) == 0); + expect(@bitreverse(u5, 0x12) == 0x9); + expect(@bitreverse(u8, 0x12) == 0x48); + expect(@bitreverse(u16, 0x1234) == 0x2c48); + expect(@bitreverse(u24, 0x123456) == 0x6a2c48); + expect(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + expect(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + expect(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + expect(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + expect(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + expect(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); // using runtime uints, unsigned var num0: u0 = 0; - assertOrPanic(@bitreverse(u0, num0) == 0); + expect(@bitreverse(u0, num0) == 0); var num5: u5 = 0x12; - assertOrPanic(@bitreverse(u5, num5) == 0x9); + expect(@bitreverse(u5, num5) == 0x9); var num8: u8 = 0x12; - assertOrPanic(@bitreverse(u8, num8) == 0x48); + expect(@bitreverse(u8, num8) == 0x48); var num16: u16 = 0x1234; - assertOrPanic(@bitreverse(u16, num16) == 0x2c48); + expect(@bitreverse(u16, num16) == 0x2c48); var num24: u24 = 0x123456; - assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48); + expect(@bitreverse(u24, num24) == 0x6a2c48); var num32: u32 = 0x12345678; - assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48); + expect(@bitreverse(u32, num32) == 0x1e6a2c48); var num40: u40 = 0x123456789a; - assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48); + expect(@bitreverse(u40, num40) == 0x591e6a2c48); var num48: u48 = 0x123456789abc; - assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48); + expect(@bitreverse(u48, num48) == 0x3d591e6a2c48); var num56: u56 = 0x123456789abcde; - assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + expect(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); var num64: u64 = 0x123456789abcdef1; - assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + expect(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); var num128: u128 = 0x123456789abcdef11121314151617181; - assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + expect(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); // using comptime_ints, signed, positive - assertOrPanic(@bitreverse(i0, 0) == 0); - assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); - assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); - assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); - assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); - assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); - assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); - assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); - assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); - assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); + expect(@bitreverse(i0, 0) == 0); + expect(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); + expect(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); + expect(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); + expect(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); + expect(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); + expect(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); + expect(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); + expect(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); + expect(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. var neg5: i5 = minInt(i5) + 1; - assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + expect(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); var neg8: i8 = -18; - assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + expect(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); var neg16: i16 = -32694; - assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + expect(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); var neg24: i24 = -6773785; - assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + expect(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); var neg32: i32 = -16773785; - assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + expect(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); var neg40: i40 = minInt(i40) + 12345; - assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + expect(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); var neg48: i48 = minInt(i48) + 12345; - assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + expect(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); var neg56: i56 = minInt(i56) + 12345; - assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + expect(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); var neg64: i64 = minInt(i64) + 12345; - assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + expect(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); var neg128: i128 = minInt(i128) + 12345; - assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); + expect(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); } diff --git a/test/stage1/behavior/bool.zig b/test/stage1/behavior/bool.zig index 2d7241526f..dfc2279005 100644 --- a/test/stage1/behavior/bool.zig +++ b/test/stage1/behavior/bool.zig @@ -1,25 +1,25 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "bool literals" { - assertOrPanic(true); - assertOrPanic(!false); + expect(true); + expect(!false); } test "cast bool to int" { const t = true; const f = false; - assertOrPanic(@boolToInt(t) == u32(1)); - assertOrPanic(@boolToInt(f) == u32(0)); + expect(@boolToInt(t) == u32(1)); + expect(@boolToInt(f) == u32(0)); nonConstCastBoolToInt(t, f); } fn nonConstCastBoolToInt(t: bool, f: bool) void { - assertOrPanic(@boolToInt(t) == u32(1)); - assertOrPanic(@boolToInt(f) == u32(0)); + expect(@boolToInt(t) == u32(1)); + expect(@boolToInt(f) == u32(0)); } test "bool cmp" { - assertOrPanic(testBoolCmp(true, false) == false); + expect(testBoolCmp(true, false) == false); } fn testBoolCmp(a: bool, b: bool) bool { return a == b; @@ -30,6 +30,6 @@ const global_t = true; const not_global_f = !global_f; const not_global_t = !global_t; test "compile time bool not" { - assertOrPanic(not_global_f); - assertOrPanic(!not_global_t); + expect(not_global_f); + expect(!not_global_t); } diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig index 8084538e03..beffa0f73a 100644 --- a/test/stage1/behavior/bswap.zig +++ b/test/stage1/behavior/bswap.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "@bswap" { comptime testByteSwap(); @@ -7,26 +7,26 @@ test "@bswap" { } fn testByteSwap() void { - assertOrPanic(@bswap(u0, 0) == 0); - assertOrPanic(@bswap(u8, 0x12) == 0x12); - assertOrPanic(@bswap(u16, 0x1234) == 0x3412); - assertOrPanic(@bswap(u24, 0x123456) == 0x563412); - assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412); - assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412); - assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); - assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); - assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); - assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + expect(@bswap(u0, 0) == 0); + expect(@bswap(u8, 0x12) == 0x12); + expect(@bswap(u16, 0x1234) == 0x3412); + expect(@bswap(u24, 0x123456) == 0x563412); + expect(@bswap(u32, 0x12345678) == 0x78563412); + expect(@bswap(u40, 0x123456789a) == 0x9a78563412); + expect(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + expect(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + expect(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + expect(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); - assertOrPanic(@bswap(i0, 0) == 0); - assertOrPanic(@bswap(i8, -50) == -50); - assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); - assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); - assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); - assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); - assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); - assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); - assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); - assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + expect(@bswap(i0, 0) == 0); + expect(@bswap(i8, -50) == -50); + expect(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + expect(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + expect(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + expect(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + expect(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + expect(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + expect(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + expect(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); } diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig index 69a7e70f7d..9dc1d111ea 100644 --- a/test/stage1/behavior/bugs/1076.zig +++ b/test/stage1/behavior/bugs/1076.zig @@ -1,6 +1,6 @@ const std = @import("std"); const mem = std.mem; -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "comptime code should not modify constant data" { testCastPtrOfArrayToSliceAndPtr(); @@ -11,6 +11,6 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "boeu")); + expect(mem.eql(u8, array[0..], "boeu")); } diff --git a/test/stage1/behavior/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig index a83e7653e2..3aa1db2ea0 100644 --- a/test/stage1/behavior/bugs/1277.zig +++ b/test/stage1/behavior/bugs/1277.zig @@ -11,5 +11,5 @@ fn f() i32 { } test "don't emit an LLVM global for a const function when it's in an optional in a struct" { - std.debug.assertOrPanic(s.f.?() == 1234); + std.testing.expect(s.f.?() == 1234); } diff --git a/test/stage1/behavior/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig index 2e67f4473f..f1d61baa3a 100644 --- a/test/stage1/behavior/bugs/1322.zig +++ b/test/stage1/behavior/bugs/1322.zig @@ -13,7 +13,7 @@ const C = struct {}; test "tagged union with all void fields but a meaningful tag" { var a: A = A{ .b = B{ .c = C{} } }; - std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c); + std.testing.expect(@TagType(B)(a.b) == @TagType(B).c); a = A{ .b = B.None }; - std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None); + std.testing.expect(@TagType(B)(a.b) == @TagType(B).None); } diff --git a/test/stage1/behavior/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig index 2d452da156..91c994d7c0 100644 --- a/test/stage1/behavior/bugs/1381.zig +++ b/test/stage1/behavior/bugs/1381.zig @@ -17,5 +17,5 @@ test "union that needs padding bytes inside an array" { }; const a = as[0].B; - std.debug.assertOrPanic(a.D == 1); + std.testing.expect(a.D == 1); } diff --git a/test/stage1/behavior/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig index fbc932781a..48cf1ae2a6 100644 --- a/test/stage1/behavior/bugs/1421.zig +++ b/test/stage1/behavior/bugs/1421.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const S = struct { fn method() builtin.TypeInfo { @@ -10,5 +10,5 @@ const S = struct { test "functions with return type required to be comptime are generic" { const ti = S.method(); - assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct); + expect(builtin.TypeId(ti) == builtin.TypeId.Struct); } diff --git a/test/stage1/behavior/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig index e9dfd5d2ce..d5ea3f66fe 100644 --- a/test/stage1/behavior/bugs/1442.zig +++ b/test/stage1/behavior/bugs/1442.zig @@ -7,5 +7,5 @@ const Union = union(enum) { test "const error union field alignment" { var union_or_err: anyerror!Union = Union{ .Color = 1234 }; - std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); + std.testing.expect((union_or_err catch unreachable).Color == 1234); } diff --git a/test/stage1/behavior/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig index 0483e3828c..d1bb8d7053 100644 --- a/test/stage1/behavior/bugs/1486.zig +++ b/test/stage1/behavior/bugs/1486.zig @@ -1,11 +1,11 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const ptr = &global; var global: u64 = 123; test "constant pointer to global variable causes runtime load" { global = 1234; - assertOrPanic(&global == ptr); - assertOrPanic(ptr.* == 1234); + expect(&global == ptr); + expect(ptr.* == 1234); } diff --git a/test/stage1/behavior/bugs/394.zig b/test/stage1/behavior/bugs/394.zig index 766ad9e157..b1f0b6b605 100644 --- a/test/stage1/behavior/bugs/394.zig +++ b/test/stage1/behavior/bugs/394.zig @@ -7,12 +7,12 @@ const S = struct { y: E, }; -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "bug 394 fixed" { const x = S{ .x = 3, .y = E{ .B = 1 }, }; - assertOrPanic(x.x == 3); + expect(x.x == 3); } diff --git a/test/stage1/behavior/bugs/655.zig b/test/stage1/behavior/bugs/655.zig index 67ba6a231f..d4491bfc27 100644 --- a/test/stage1/behavior/bugs/655.zig +++ b/test/stage1/behavior/bugs/655.zig @@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig"); test "function with *const parameter with type dereferenced by namespace" { const x: other_file.Integer = 1234; - comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer); + comptime std.testing.expect(@typeOf(&x) == *const other_file.Integer); foo(&x); } fn foo(x: *const other_file.Integer) void { - std.debug.assertOrPanic(x.* == 1234); + std.testing.expect(x.* == 1234); } diff --git a/test/stage1/behavior/bugs/656.zig b/test/stage1/behavior/bugs/656.zig index cb37fe67fe..159ec52d43 100644 --- a/test/stage1/behavior/bugs/656.zig +++ b/test/stage1/behavior/bugs/656.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const PrefixOp = union(enum) { Return, @@ -22,7 +22,7 @@ fn foo(a: bool, b: bool) void { PrefixOp.AddrOf => |addr_of_info| { if (b) {} if (addr_of_info.align_expr) |align_expr| { - assertOrPanic(align_expr == 1234); + expect(align_expr == 1234); } }, PrefixOp.Return => {}, diff --git a/test/stage1/behavior/bugs/726.zig b/test/stage1/behavior/bugs/726.zig index ce20480c63..dd2a135b56 100644 --- a/test/stage1/behavior/bugs/726.zig +++ b/test/stage1/behavior/bugs/726.zig @@ -1,9 +1,9 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@ptrCast from const to nullable" { const c: u8 = 4; var x: ?*const u8 = @ptrCast(?*const u8, &c); - assertOrPanic(x.?.* == 4); + expect(x.?.* == 4); } test "@ptrCast from var in empty struct to nullable" { @@ -11,6 +11,6 @@ test "@ptrCast from var in empty struct to nullable" { var c: u8 = 4; }; var x: ?*const u8 = @ptrCast(?*const u8, &container.c); - assertOrPanic(x.?.* == 4); + expect(x.?.* == 4); } diff --git a/test/stage1/behavior/bugs/920.zig b/test/stage1/behavior/bugs/920.zig index e29c5c4acf..10c002f6ba 100644 --- a/test/stage1/behavior/bugs/920.zig +++ b/test/stage1/behavior/bugs/920.zig @@ -60,6 +60,6 @@ test "bug 920 fixed" { }; for (NormalDist1.f) |_, i| { - std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]); + std.testing.expect(NormalDist1.f[i] == NormalDist.f[i]); } } diff --git a/test/stage1/behavior/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig index 14ee212ce0..3794a965c6 100644 --- a/test/stage1/behavior/byval_arg_var.zig +++ b/test/stage1/behavior/byval_arg_var.zig @@ -6,7 +6,7 @@ test "pass string literal byvalue to a generic var param" { start(); blowUpStack(10); - std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal")); + std.testing.expect(std.mem.eql(u8, result, "string literal")); } fn start() void { diff --git a/test/stage1/behavior/cancel.zig b/test/stage1/behavior/cancel.zig index 863da4bdb8..7fadf7f230 100644 --- a/test/stage1/behavior/cancel.zig +++ b/test/stage1/behavior/cancel.zig @@ -10,9 +10,9 @@ test "cancel forwards" { const p = async<&da.allocator> f1() catch unreachable; cancel p; - std.debug.assertOrPanic(defer_f1); - std.debug.assertOrPanic(defer_f2); - std.debug.assertOrPanic(defer_f3); + std.testing.expect(defer_f1); + std.testing.expect(defer_f2); + std.testing.expect(defer_f3); } async fn f1() void { @@ -47,10 +47,10 @@ test "cancel backwards" { const p = async<&da.allocator> b1() catch unreachable; cancel p; - std.debug.assertOrPanic(defer_b1); - std.debug.assertOrPanic(defer_b2); - std.debug.assertOrPanic(defer_b3); - std.debug.assertOrPanic(defer_b4); + std.testing.expect(defer_b1); + std.testing.expect(defer_b2); + std.testing.expect(defer_b3); + std.testing.expect(defer_b4); } async fn b1() void { diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 27f685a96e..8ed03f4936 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; const maxInt = std.math.maxInt; @@ -7,12 +7,12 @@ test "int to ptr cast" { const x = usize(13); const y = @intToPtr(*u8, x); const z = @ptrToInt(y); - assertOrPanic(z == 13); + expect(z == 13); } test "integer literal to pointer cast" { const vga_mem = @intToPtr(*u16, 0xB8000); - assertOrPanic(@ptrToInt(vga_mem) == 0xB8000); + expect(@ptrToInt(vga_mem) == 0xB8000); } test "pointer reinterpret const float to int" { @@ -20,7 +20,7 @@ test "pointer reinterpret const float to int" { const float_ptr = &float; const int_ptr = @ptrCast(*const i32, float_ptr); const int_val = int_ptr.*; - assertOrPanic(int_val == 858993411); + expect(int_val == 858993411); } test "implicitly cast indirect pointer to maybe-indirect pointer" { @@ -44,10 +44,10 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" { const p = &s; const q = &p; const r = &q; - assertOrPanic(42 == S.constConst(q)); - assertOrPanic(42 == S.maybeConstConst(q)); - assertOrPanic(42 == S.constConstConst(r)); - assertOrPanic(42 == S.maybeConstConstConst(r)); + expect(42 == S.constConst(q)); + expect(42 == S.maybeConstConst(q)); + expect(42 == S.constConstConst(r)); + expect(42 == S.maybeConstConstConst(r)); } test "explicit cast from integer to error type" { @@ -57,14 +57,14 @@ test "explicit cast from integer to error type" { fn testCastIntToErr(err: anyerror) void { const x = @errorToInt(err); const y = @intToError(x); - assertOrPanic(error.ItBroke == y); + expect(error.ItBroke == y); } test "peer resolve arrays of different size to const slice" { - assertOrPanic(mem.eql(u8, boolToStr(true), "true")); - assertOrPanic(mem.eql(u8, boolToStr(false), "false")); - comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true")); - comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false")); + expect(mem.eql(u8, boolToStr(true), "true")); + expect(mem.eql(u8, boolToStr(false), "false")); + comptime expect(mem.eql(u8, boolToStr(true), "true")); + comptime expect(mem.eql(u8, boolToStr(false), "false")); } fn boolToStr(b: bool) []const u8 { return if (b) "true" else "false"; @@ -77,8 +77,8 @@ test "peer resolve array and const slice" { fn testPeerResolveArrayConstSlice(b: bool) void { const value1 = if (b) "aoeu" else ([]const u8)("zz"); const value2 = if (b) ([]const u8)("zz") else "aoeu"; - assertOrPanic(mem.eql(u8, value1, "aoeu")); - assertOrPanic(mem.eql(u8, value2, "zz")); + expect(mem.eql(u8, value1, "aoeu")); + expect(mem.eql(u8, value2, "zz")); } test "implicitly cast from T to anyerror!?T" { @@ -92,14 +92,14 @@ const A = struct { fn castToOptionalTypeError(z: i32) void { const x = i32(1); const y: anyerror!?i32 = x; - assertOrPanic((try y).? == 1); + expect((try y).? == 1); const f = z; const g: anyerror!?i32 = f; const a = A{ .a = z }; const b: anyerror!?A = a; - assertOrPanic((b catch unreachable).?.a == 1); + expect((b catch unreachable).?.a == 1); } test "implicitly cast from int to anyerror!?T" { @@ -114,7 +114,7 @@ fn implicitIntLitToOptional() void { test "return null from fn() anyerror!?&T" { const a = returnNullFromOptionalTypeErrorRef(); const b = returnNullLitFromOptionalTypeErrorRef(); - assertOrPanic((try a) == null and (try b) == null); + expect((try a) == null and (try b) == null); } fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { const a: ?*A = null; @@ -125,11 +125,11 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { } test "peer type resolution: ?T and T" { - assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); - assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); comptime { - assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); - assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); } } fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { @@ -141,11 +141,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { } test "peer type resolution: [0]u8 and []const u8" { - assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); comptime { - assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); } } fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { @@ -157,8 +157,8 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { } test "implicitly cast from [N]T to ?[]const T" { - assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); - comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); + expect(mem.eql(u8, castToOptionalSlice().?, "hi")); + comptime expect(mem.eql(u8, castToOptionalSlice().?, "hi")); } fn castToOptionalSlice() ?[]const u8 { @@ -171,7 +171,7 @@ test "implicitly cast from [0]T to anyerror![]T" { } fn testCastZeroArrayToErrSliceMut() void { - assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0); + expect((gimmeErrOrSlice() catch unreachable).len == 0); } fn gimmeErrOrSlice() anyerror![]u8 { @@ -182,14 +182,14 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { { var data = "hi"; const slice = data[0..]; - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } comptime { var data = "hi"; const slice = data[0..]; - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } } fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { @@ -207,7 +207,7 @@ test "resolve undefined with integer" { fn testResolveUndefWithInt(b: bool, x: i32) void { const value = if (b) x else undefined; if (b) { - assertOrPanic(value == x); + expect(value == x); } } @@ -219,17 +219,17 @@ test "implicit cast from &const [N]T to []const T" { fn testCastConstArrayRefToConstSlice() void { const blah = "aoeu"; const const_array_ref = &blah; - assertOrPanic(@typeOf(const_array_ref) == *const [4]u8); + expect(@typeOf(const_array_ref) == *const [4]u8); const slice: []const u8 = const_array_ref; - assertOrPanic(mem.eql(u8, slice, "aoeu")); + expect(mem.eql(u8, slice, "aoeu")); } test "peer type resolution: error and [N]T" { // TODO: implicit error!T to error!U where T can implicitly cast to U - //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); - comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + //expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + //comptime expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + comptime expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); } //fn testPeerErrorAndArray(x: u8) error![]const u8 { @@ -253,9 +253,9 @@ test "@floatToInt" { fn testFloatToInts() void { const x = i32(1e4); - assertOrPanic(x == 10000); + expect(x == 10000); const y = @floatToInt(i32, f32(1e4)); - assertOrPanic(y == 10000); + expect(y == 10000); expectFloatToInt(f16, 255.1, u8, 255); expectFloatToInt(f16, 127.2, i8, 127); expectFloatToInt(f16, -128.2, i8, -128); @@ -266,7 +266,7 @@ fn testFloatToInts() void { } fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { - assertOrPanic(@floatToInt(I, f) == i); + expect(@floatToInt(I, f) == i); } test "cast u128 to f128 and back" { @@ -275,7 +275,7 @@ test "cast u128 to f128 and back" { } fn testCast128() void { - assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); + expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); } fn cast128Int(x: f128) u128 { @@ -295,9 +295,9 @@ test "const slice widen cast" { }; const u32_value = @bytesToSlice(u32, bytes[0..])[0]; - assertOrPanic(u32_value == 0x12121212); + expect(u32_value == 0x12121212); - assertOrPanic(@bitCast(u32, bytes) == 0x12121212); + expect(@bitCast(u32, bytes) == 0x12121212); } test "single-item pointer of array to slice and to unknown length pointer" { @@ -309,76 +309,76 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "boeu")); + expect(mem.eql(u8, array[0..], "boeu")); const y: []u8 = &array; y[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "coeu")); + expect(mem.eql(u8, array[0..], "coeu")); } test "cast *[1][*]const u8 to [*]const ?[*]const u8" { const window_name = [1][*]const u8{c"window name"}; const x: [*]const ?[*]const u8 = &window_name; - assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); + expect(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); } test "@intCast comptime_int" { const result = @intCast(i32, 1234); - assertOrPanic(@typeOf(result) == i32); - assertOrPanic(result == 1234); + expect(@typeOf(result) == i32); + expect(result == 1234); } test "@floatCast comptime_int and comptime_float" { { const result = @floatCast(f16, 1234); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @floatCast(f16, 1234.0); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @floatCast(f32, 1234); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } { const result = @floatCast(f32, 1234.0); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } } test "comptime_int @intToFloat" { { const result = @intToFloat(f16, 1234); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @intToFloat(f32, 1234); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } } test "@bytesToSlice keeps pointer alignment" { var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; const numbers = @bytesToSlice(u32, bytes[0..]); - comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); + comptime expect(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); } test "@intCast i32 to u7" { var x: u128 = maxInt(u128); var y: i32 = 120; var z = x >> @intCast(u7, y); - assertOrPanic(z == 0xff); + expect(z == 0xff); } test "implicit cast undefined to optional" { - assertOrPanic(MakeType(void).getNull() == null); - assertOrPanic(MakeType(void).getNonNull() != null); + expect(MakeType(void).getNull() == null); + expect(MakeType(void).getNonNull() != null); } fn MakeType(comptime T: type) type { @@ -398,16 +398,16 @@ test "implicit cast from *[N]T to ?[*]T" { var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; x = &y; - assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); + expect(std.mem.eql(u16, x.?[0..4], y[0..4])); x.?[0] = 8; y[3] = 6; - assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); + expect(std.mem.eql(u16, x.?[0..4], y[0..4])); } test "implicit cast from *T to ?*c_void" { var a: u8 = 1; incrementVoidPtrValue(&a); - std.debug.assertOrPanic(a == 2); + std.testing.expect(a == 2); } fn incrementVoidPtrValue(value: ?*c_void) void { @@ -417,7 +417,7 @@ fn incrementVoidPtrValue(value: ?*c_void) void { test "implicit cast from [*]T to ?*c_void" { var a = []u8{ 3, 2, 1 }; incrementVoidPtrArray(a[0..].ptr, 3); - assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); + expect(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); } fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { @@ -441,27 +441,27 @@ pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); pub const PFN_void = extern fn (*c_void) void; fn foobar(func: PFN_void) void { - std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize)); + std.testing.expect(@ptrToInt(func) == maxInt(usize)); } test "implicit ptr to *c_void" { var a: u32 = 1; var ptr: *c_void = &a; var b: *u32 = @ptrCast(*u32, ptr); - assertOrPanic(b.* == 1); + expect(b.* == 1); var ptr2: ?*c_void = &a; var c: *u32 = @ptrCast(*u32, ptr2.?); - assertOrPanic(c.* == 1); + expect(c.* == 1); } test "@intCast to comptime_int" { - assertOrPanic(@intCast(comptime_int, 0) == 0); + expect(@intCast(comptime_int, 0) == 0); } test "implicit cast comptime numbers to any type when the value fits" { const a: u64 = 255; var b: u8 = a; - assertOrPanic(b == 255); + expect(b == 255); } test "@intToEnum passed a comptime_int to an enum with one item" { @@ -469,14 +469,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" { A, }; const x = @intToEnum(E, 0); - assertOrPanic(x == E.A); + expect(x == E.A); } test "@intCast to u0 and use the result" { const S = struct { fn doTheTest(zero: u1, one: u1, bigzero: i32) void { - assertOrPanic((one << @intCast(u0, bigzero)) == 1); - assertOrPanic((zero << @intCast(u0, bigzero)) == 0); + expect((one << @intCast(u0, bigzero)) == 1); + expect((zero << @intCast(u0, bigzero)) == 0); } }; S.doTheTest(0, 1, 0); diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index 5b9b70a558..57044d8aae 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -1,5 +1,6 @@ -const debug = @import("std").debug; -const assertOrPanic = debug.assertOrPanic; +const std = @import("std"); +const debug = std.debug; +const expect = std.testing.expect; var argv: [*]const [*]const u8 = undefined; @@ -15,10 +16,10 @@ test "const slice child" { } fn foo(args: [][]const u8) void { - assertOrPanic(args.len == 3); - assertOrPanic(streql(args[0], "one")); - assertOrPanic(streql(args[1], "two")); - assertOrPanic(streql(args[2], "three")); + expect(args.len == 3); + expect(streql(args[0], "one")); + expect(streql(args[1], "two")); + expect(streql(args[2], "three")); } fn bar(argc: usize) void { diff --git a/test/stage1/behavior/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig index 6ca2a301ec..29f77bf67c 100644 --- a/test/stage1/behavior/coroutine_await_struct.zig +++ b/test/stage1/behavior/coroutine_await_struct.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const Foo = struct { x: i32, @@ -18,8 +18,8 @@ test "coroutine await struct" { await_seq('f'); resume await_a_promise; await_seq('i'); - assertOrPanic(await_final_result.x == 1234); - assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); + expect(await_final_result.x == 1234); + expect(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig index a2327c5060..be977bbfce 100644 --- a/test/stage1/behavior/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; var x: i32 = 1; @@ -9,9 +9,9 @@ test "create a coroutine and cancel it" { defer da.deinit(); const p = try async<&da.allocator> simpleAsyncFn(); - comptime assertOrPanic(@typeOf(p) == promise->void); + comptime expect(@typeOf(p) == promise->void); cancel p; - assertOrPanic(x == 2); + expect(x == 2); } async fn simpleAsyncFn() void { x += 1; @@ -31,7 +31,7 @@ test "coroutine suspend, resume, cancel" { cancel p; seq('g'); - assertOrPanic(std.mem.eql(u8, points, "abcdefg")); + expect(std.mem.eql(u8, points, "abcdefg")); } async fn testAsyncSeq() void { defer seq('e'); @@ -53,9 +53,9 @@ test "coroutine suspend with block" { defer da.deinit(); const p = try async<&da.allocator> testSuspendBlock(); - std.debug.assertOrPanic(!result); + std.testing.expect(!result); resume a_promise; - std.debug.assertOrPanic(result); + std.testing.expect(result); cancel p; } @@ -63,13 +63,13 @@ var a_promise: promise = undefined; var result = false; async fn testSuspendBlock() void { suspend { - comptime assertOrPanic(@typeOf(@handle()) == promise->void); + comptime expect(@typeOf(@handle()) == promise->void); a_promise = @handle(); } //Test to make sure that @handle() works as advertised (issue #1296) //var our_handle: promise = @handle(); - assertOrPanic(a_promise == @handle()); + expect(a_promise == @handle()); result = true; } @@ -86,8 +86,8 @@ test "coroutine await" { await_seq('f'); resume await_a_promise; await_seq('i'); - assertOrPanic(await_final_result == 1234); - assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); + expect(await_final_result == 1234); + expect(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); @@ -123,8 +123,8 @@ test "coroutine await early return" { early_seq('a'); const p = async<&da.allocator> early_amain() catch @panic("out of memory"); early_seq('f'); - assertOrPanic(early_final_result == 1234); - assertOrPanic(std.mem.eql(u8, early_points, "abcdef")); + expect(early_final_result == 1234); + expect(std.mem.eql(u8, early_points, "abcdef")); } async fn early_amain() void { early_seq('b'); @@ -170,7 +170,7 @@ test "async function with dot syntax" { defer da.deinit(); const p = try async<&da.allocator> S.foo(); cancel p; - assertOrPanic(S.y == 2); + expect(S.y == 2); } test "async fn pointer in a struct field" { @@ -182,9 +182,9 @@ test "async fn pointer in a struct field" { var da = std.heap.DirectAllocator.init(); defer da.deinit(); const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; - assertOrPanic(data == 2); + expect(data == 2); cancel p; - assertOrPanic(data == 4); + expect(data == 4); } async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { defer y.* += 2; @@ -230,9 +230,9 @@ async fn suspendThenFail() anyerror!void { } async fn printTrace(p: promise->(anyerror!void)) void { (await p) catch |e| { - std.debug.assertOrPanic(e == error.Fail); + std.testing.expect(e == error.Fail); if (@errorReturnTrace()) |trace| { - assertOrPanic(trace.index == 1); + expect(trace.index == 1); } else switch (builtin.mode) { builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, @@ -246,7 +246,7 @@ test "break from suspend" { var my_result: i32 = 1; const p = try async
testBreakFromSuspend(&my_result); cancel p; - std.debug.assertOrPanic(my_result == 2); + std.testing.expect(my_result == 2); } async fn testBreakFromSuspend(my_result: *i32) void { suspend { diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig index 6c6c60311e..0bb9125e7c 100644 --- a/test/stage1/behavior/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; var result: [3]u8 = undefined; var index: usize = undefined; @@ -21,18 +21,18 @@ fn runSomeErrorDefers(x: bool) !bool { } test "mixing normal and error defers" { - assertOrPanic(runSomeErrorDefers(true) catch unreachable); - assertOrPanic(result[0] == 'c'); - assertOrPanic(result[1] == 'a'); + expect(runSomeErrorDefers(true) catch unreachable); + expect(result[0] == 'c'); + expect(result[1] == 'a'); const ok = runSomeErrorDefers(false) catch |err| x: { - assertOrPanic(err == error.FalseNotAllowed); + expect(err == error.FalseNotAllowed); break :x true; }; - assertOrPanic(ok); - assertOrPanic(result[0] == 'c'); - assertOrPanic(result[1] == 'b'); - assertOrPanic(result[2] == 'a'); + expect(ok); + expect(result[0] == 'c'); + expect(result[1] == 'b'); + expect(result[2] == 'a'); } test "break and continue inside loop inside defer expression" { @@ -47,7 +47,7 @@ fn testBreakContInDefer(x: usize) void { if (i < 5) continue; if (i == 5) break; } - assertOrPanic(i == 5); + expect(i == 5); } } @@ -59,11 +59,11 @@ test "defer and labeled break" { break :blk; } - assertOrPanic(i == 1); + expect(i == 1); } test "errdefer does not apply to fn inside fn" { - if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad); + if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| expect(e == error.Bad); } fn testNestedFnErrDefer() anyerror!void { diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 9de138ef78..899aeea67d 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; test "enum type" { @@ -11,16 +11,16 @@ test "enum type" { }; const bar = Bar.B; - assertOrPanic(bar == Bar.B); - assertOrPanic(@memberCount(Foo) == 3); - assertOrPanic(@memberCount(Bar) == 4); - assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - assertOrPanic(@sizeOf(Bar) == 1); + expect(bar == Bar.B); + expect(@memberCount(Foo) == 3); + expect(@memberCount(Bar) == 4); + expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + expect(@sizeOf(Bar) == 1); } test "enum as return value" { switch (returnAnInt(13)) { - Foo.One => |value| assertOrPanic(value == 13), + Foo.One => |value| expect(value == 13), else => unreachable, } } @@ -92,14 +92,14 @@ test "enum to int" { } fn shouldEqual(n: Number, expected: u3) void { - assertOrPanic(@enumToInt(n) == expected); + expect(@enumToInt(n) == expected); } test "int to enum" { testIntToEnumEval(3); } fn testIntToEnumEval(x: i32) void { - assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); + expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); } const IntToEnumNumber = enum { Zero, @@ -110,8 +110,8 @@ const IntToEnumNumber = enum { }; test "@tagName" { - assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); - comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); } fn testEnumTagNameBare(n: BareNumber) []const u8 { @@ -126,8 +126,8 @@ const BareNumber = enum { test "enum alignment" { comptime { - assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); - assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64)); + expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); + expect(@alignOf(AlignTestEnum) >= @alignOf(u64)); } } @@ -663,10 +663,10 @@ const ValueCount257 = enum { test "enum sizes" { comptime { - assertOrPanic(@sizeOf(ValueCount1) == 0); - assertOrPanic(@sizeOf(ValueCount2) == 1); - assertOrPanic(@sizeOf(ValueCount256) == 1); - assertOrPanic(@sizeOf(ValueCount257) == 2); + expect(@sizeOf(ValueCount1) == 0); + expect(@sizeOf(ValueCount2) == 1); + expect(@sizeOf(ValueCount256) == 1); + expect(@sizeOf(ValueCount257) == 2); } } @@ -685,12 +685,12 @@ test "set enum tag type" { { var x = Small.One; x = Small.Two; - comptime assertOrPanic(@TagType(Small) == u2); + comptime expect(@TagType(Small) == u2); } { var x = Small2.One; x = Small2.Two; - comptime assertOrPanic(@TagType(Small2) == u2); + comptime expect(@TagType(Small2) == u2); } } @@ -737,17 +737,17 @@ const bit_field_1 = BitFieldOfEnums{ test "bit field access with enum fields" { var data = bit_field_1; - assertOrPanic(getA(&data) == A.Two); - assertOrPanic(getB(&data) == B.Three3); - assertOrPanic(getC(&data) == C.Four4); - comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1); + expect(getA(&data) == A.Two); + expect(getB(&data) == B.Three3); + expect(getC(&data) == C.Four4); + comptime expect(@sizeOf(BitFieldOfEnums) == 1); data.b = B.Four3; - assertOrPanic(data.b == B.Four3); + expect(data.b == B.Four3); data.a = A.Three; - assertOrPanic(data.a == A.Three); - assertOrPanic(data.b == B.Four3); + expect(data.a == A.Three); + expect(data.b == B.Four3); } fn getA(data: *const BitFieldOfEnums) A { @@ -768,7 +768,7 @@ test "casting enum to its tag type" { } fn testCastEnumToTagType(value: Small2) void { - assertOrPanic(@enumToInt(value) == 1); + expect(@enumToInt(value) == 1); } const MultipleChoice = enum(u32) { @@ -784,8 +784,8 @@ test "enum with specified tag values" { } fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { - assertOrPanic(@enumToInt(x) == 60); - assertOrPanic(1234 == switch (x) { + expect(@enumToInt(x) == 60); + expect(1234 == switch (x) { MultipleChoice.A => 1, MultipleChoice.B => 2, MultipleChoice.C => u32(1234), @@ -811,8 +811,8 @@ test "enum with specified and unspecified tag values" { } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assertOrPanic(@enumToInt(x) == 1000); - assertOrPanic(1234 == switch (x) { + expect(@enumToInt(x) == 1000); + expect(1234 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => 3, @@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { } test "cast integer literal to enum" { - assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); - assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); + expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); + expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); } const EnumWithOneMember = enum { @@ -865,14 +865,14 @@ const EnumWithTagValues = enum(u4) { D = 1 << 3, }; test "enum with tag values don't require parens" { - assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100); + expect(@enumToInt(EnumWithTagValues.C) == 0b0100); } test "enum with 1 field but explicit tag type should still have the tag type" { const Enum = enum(u8) { B = 2, }; - comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8)); + comptime @import("std").testing.expect(@sizeOf(Enum) == @sizeOf(u8)); } test "empty extern enum with members" { @@ -881,7 +881,7 @@ test "empty extern enum with members" { B, C, }; - assertOrPanic(@sizeOf(E) == @sizeOf(c_int)); + expect(@sizeOf(E) == @sizeOf(c_int)); } test "tag name with assigned enum values" { @@ -890,5 +890,5 @@ test "tag name with assigned enum values" { B = 0, }; var b = LocalFoo.B; - assertOrPanic(mem.eql(u8, @tagName(b), "B")); + expect(mem.eql(u8, @tagName(b), "B")); } diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig index 49af1ceae7..2e022a3427 100644 --- a/test/stage1/behavior/enum_with_members.zig +++ b/test/stage1/behavior/enum_with_members.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const fmt = @import("std").fmt; @@ -19,9 +19,9 @@ test "enum with members" { const b = ET{ .UINT = 42 }; var buf: [20]u8 = undefined; - assertOrPanic((a.print(buf[0..]) catch unreachable) == 3); - assertOrPanic(mem.eql(u8, buf[0..3], "-42")); + expect((a.print(buf[0..]) catch unreachable) == 3); + expect(mem.eql(u8, buf[0..3], "-42")); - assertOrPanic((b.print(buf[0..]) catch unreachable) == 2); - assertOrPanic(mem.eql(u8, buf[0..2], "42")); + expect((b.print(buf[0..]) catch unreachable) == 2); + expect(mem.eql(u8, buf[0..2], "42")); } diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index c7e38712bc..265ddd9d6c 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; -const assertError = std.debug.assertError; +const expect = std.testing.expect; +const expectError = std.testing.expectError; const mem = std.mem; const builtin = @import("builtin"); @@ -19,7 +19,7 @@ pub fn baz() anyerror!i32 { } test "error wrapping" { - assertOrPanic((baz() catch unreachable) == 15); + expect((baz() catch unreachable) == 15); } fn gimmeItBroke() []const u8 { @@ -27,14 +27,14 @@ fn gimmeItBroke() []const u8 { } test "@errorName" { - assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError")); - assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); + expect(mem.eql(u8, @errorName(error.AnError), "AnError")); + expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); } test "error values" { const a = @errorToInt(error.err1); const b = @errorToInt(error.err2); - assertOrPanic(a != b); + expect(a != b); } test "redefinition of error values allowed" { @@ -47,8 +47,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { test "error binary operator" { const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; - assertOrPanic(a == 3); - assertOrPanic(b == 10); + expect(a == 3); + expect(b == 10); } fn errBinaryOperatorG(x: bool) anyerror!isize { return if (x) error.ItBroke else isize(10); @@ -56,7 +56,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize { test "unwrap simple value from error" { const i = unwrapSimpleValueFromErrorDo() catch unreachable; - assertOrPanic(i == 13); + expect(i == 13); } fn unwrapSimpleValueFromErrorDo() anyerror!isize { return 13; @@ -82,10 +82,10 @@ test "error union type " { fn testErrorUnionType() void { const x: anyerror!i32 = 1234; - if (x) |value| assertOrPanic(value == 1234) else |_| unreachable; - assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); - assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); - assertOrPanic(@typeOf(x).ErrorSet == anyerror); + if (x) |value| expect(value == 1234) else |_| unreachable; + expect(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); + expect(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); + expect(@typeOf(x).ErrorSet == anyerror); } test "error set type" { @@ -99,12 +99,12 @@ const MyErrSet = error{ }; fn testErrorSetType() void { - assertOrPanic(@memberCount(MyErrSet) == 2); + expect(@memberCount(MyErrSet) == 2); const a: MyErrSet!i32 = 5678; const b: MyErrSet!i32 = MyErrSet.OutOfMemory; - if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) { + if (a) |value| expect(value == 5678) else |err| switch (err) { error.OutOfMemory => unreachable, error.FileNotFound => unreachable, } @@ -127,7 +127,7 @@ const Set2 = error{ fn testExplicitErrorSetCast(set1: Set1) void { var x = @errSetCast(Set2, set1); var y = @errSetCast(Set1, x); - assertOrPanic(y == error.A); + expect(y == error.A); } test "comptime test error for empty error set" { @@ -138,12 +138,12 @@ test "comptime test error for empty error set" { const EmptyErrorSet = error{}; fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { - if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad"); + if (x) |v| expect(v == 1234) else |err| @compileError("bad"); } test "syntax: optional operator in front of error union operator" { comptime { - assertOrPanic(?(anyerror!i32) == ?(anyerror!i32)); + expect(?(anyerror!i32) == ?(anyerror!i32)); } } @@ -173,7 +173,7 @@ fn testErrorUnionPeerTypeResolution(x: i32) void { if (y) |_| { @panic("expected error"); } else |e| { - assertOrPanic(e == error.A); + expect(e == error.A); } } @@ -282,13 +282,13 @@ test "nested error union function call in optional unwrap" { return null; } }; - assertOrPanic((try S.errorable()) == 1234); - assertError(S.errorable2(), error.Failure); - assertError(S.errorable3(), error.Other); + expect((try S.errorable()) == 1234); + expectError(error.Failure, S.errorable2()); + expectError(error.Other, S.errorable3()); comptime { - assertOrPanic((try S.errorable()) == 1234); - assertError(S.errorable2(), error.Failure); - assertError(S.errorable3(), error.Other); + expect((try S.errorable()) == 1234); + expectError(error.Failure, S.errorable2()); + expectError(error.Other, S.errorable3()); } } @@ -303,7 +303,7 @@ test "widen cast integer payload of error union function call" { return 1234; } }; - assertOrPanic((try S.errorable()) == 1234); + expect((try S.errorable()) == 1234); } test "return function call to error set from error union function" { @@ -316,17 +316,17 @@ test "return function call to error set from error union function" { return error.Failure; } }; - assertError(S.errorable(), error.Failure); - comptime assertError(S.errorable(), error.Failure); + expectError(error.Failure, S.errorable()); + comptime expectError(error.Failure, S.errorable()); } test "optional error set is the same size as error set" { - comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror)); + comptime expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); const S = struct { fn returnsOptErrSet() ?anyerror { return null; } }; - assertOrPanic(S.returnsOptErrSet() == null); - comptime assertOrPanic(S.returnsOptErrSet() == null); + expect(S.returnsOptErrSet() == null); + comptime expect(S.returnsOptErrSet() == null); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 0d1ecfab5b..5976761f77 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); test "compile time recursion" { - assertOrPanic(some_data.len == 21); + expect(some_data.len == 21); } var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; fn fibonacci(x: i32) i32 { @@ -16,7 +16,7 @@ fn unwrapAndAddOne(blah: ?i32) i32 { } const should_be_1235 = unwrapAndAddOne(1234); test "static add one" { - assertOrPanic(should_be_1235 == 1235); + expect(should_be_1235 == 1235); } test "inlined loop" { @@ -24,7 +24,7 @@ test "inlined loop" { comptime var sum = 0; inline while (i <= 5) : (i += 1) sum += i; - assertOrPanic(sum == 15); + expect(sum == 15); } fn gimme1or2(comptime a: bool) i32 { @@ -34,12 +34,12 @@ fn gimme1or2(comptime a: bool) i32 { return z; } test "inline variable gets result of const if" { - assertOrPanic(gimme1or2(true) == 1); - assertOrPanic(gimme1or2(false) == 2); + expect(gimme1or2(true) == 1); + expect(gimme1or2(false) == 2); } test "static function evaluation" { - assertOrPanic(statically_added_number == 3); + expect(statically_added_number == 3); } const statically_added_number = staticAdd(1, 2); fn staticAdd(a: i32, b: i32) i32 { @@ -47,8 +47,8 @@ fn staticAdd(a: i32, b: i32) i32 { } test "const expr eval on single expr blocks" { - assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); - comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + comptime expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); } fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { @@ -64,10 +64,10 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { } test "statically initialized list" { - assertOrPanic(static_point_list[0].x == 1); - assertOrPanic(static_point_list[0].y == 2); - assertOrPanic(static_point_list[1].x == 3); - assertOrPanic(static_point_list[1].y == 4); + expect(static_point_list[0].x == 1); + expect(static_point_list[0].y == 2); + expect(static_point_list[1].x == 3); + expect(static_point_list[1].y == 4); } const Point = struct { x: i32, @@ -85,8 +85,8 @@ fn makePoint(x: i32, y: i32) Point { } test "static eval list init" { - assertOrPanic(static_vec3.data[2] == 1.0); - assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0); + expect(static_vec3.data[2] == 1.0); + expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); } const static_vec3 = vec3(0.0, 0.0, 1.0); pub const Vec3 = struct { @@ -102,12 +102,12 @@ pub fn vec3(x: f32, y: f32, z: f32) Vec3 { test "constant expressions" { var array: [array_size]u8 = undefined; - assertOrPanic(@sizeOf(@typeOf(array)) == 20); + expect(@sizeOf(@typeOf(array)) == 20); } const array_size: u8 = 20; test "constant struct with negation" { - assertOrPanic(vertices[0].x == -0.6); + expect(vertices[0].x == -0.6); } const Vertex = struct { x: f32, @@ -142,7 +142,7 @@ const vertices = []Vertex{ test "statically initialized struct" { st_init_str_foo.x += 1; - assertOrPanic(st_init_str_foo.x == 14); + expect(st_init_str_foo.x == 14); } const StInitStrFoo = struct { x: i32, @@ -155,7 +155,7 @@ var st_init_str_foo = StInitStrFoo{ test "statically initalized array literal" { const y: [4]u8 = st_init_arr_lit_x; - assertOrPanic(y[3] == 4); + expect(y[3] == 4); } const st_init_arr_lit_x = []u8{ 1, @@ -167,15 +167,15 @@ const st_init_arr_lit_x = []u8{ test "const slice" { comptime { const a = "1234567890"; - assertOrPanic(a.len == 10); + expect(a.len == 10); const b = a[1..2]; - assertOrPanic(b.len == 1); - assertOrPanic(b[0] == '2'); + expect(b.len == 1); + expect(b[0] == '2'); } } test "try to trick eval with runtime if" { - assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10); + expect(testTryToTrickEvalWithRuntimeIf(true) == 10); } fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { @@ -201,16 +201,16 @@ fn letsTryToCompareBools(a: bool, b: bool) bool { return max(bool, a, b); } test "inlined block and runtime block phi" { - assertOrPanic(letsTryToCompareBools(true, true)); - assertOrPanic(letsTryToCompareBools(true, false)); - assertOrPanic(letsTryToCompareBools(false, true)); - assertOrPanic(!letsTryToCompareBools(false, false)); + expect(letsTryToCompareBools(true, true)); + expect(letsTryToCompareBools(true, false)); + expect(letsTryToCompareBools(false, true)); + expect(!letsTryToCompareBools(false, false)); comptime { - assertOrPanic(letsTryToCompareBools(true, true)); - assertOrPanic(letsTryToCompareBools(true, false)); - assertOrPanic(letsTryToCompareBools(false, true)); - assertOrPanic(!letsTryToCompareBools(false, false)); + expect(letsTryToCompareBools(true, true)); + expect(letsTryToCompareBools(true, false)); + expect(letsTryToCompareBools(false, true)); + expect(!letsTryToCompareBools(false, false)); } } @@ -255,14 +255,14 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 { } test "comptime iterate over fn ptr list" { - assertOrPanic(performFn('t', 1) == 6); - assertOrPanic(performFn('o', 0) == 1); - assertOrPanic(performFn('w', 99) == 99); + expect(performFn('t', 1) == 6); + expect(performFn('o', 0) == 1); + expect(performFn('w', 99) == 99); } test "eval @setRuntimeSafety at compile-time" { const result = comptime fnWithSetRuntimeSafety(); - assertOrPanic(result == 1234); + expect(result == 1234); } fn fnWithSetRuntimeSafety() i32 { @@ -272,7 +272,7 @@ fn fnWithSetRuntimeSafety() i32 { test "eval @setFloatMode at compile-time" { const result = comptime fnWithFloatMode(); - assertOrPanic(result == 1234.0); + expect(result == 1234.0); } fn fnWithFloatMode() f32 { @@ -293,15 +293,15 @@ var simple_struct = SimpleStruct{ .field = 1234 }; const bound_fn = simple_struct.method; test "call method on bound fn referring to var instance" { - assertOrPanic(bound_fn() == 1237); + expect(bound_fn() == 1237); } test "ptr to local array argument at comptime" { comptime { var bytes: [10]u8 = undefined; modifySomeBytes(bytes[0..]); - assertOrPanic(bytes[0] == 'a'); - assertOrPanic(bytes[9] == 'b'); + expect(bytes[0] == 'a'); + expect(bytes[9] == 'b'); } } @@ -329,9 +329,9 @@ fn testCompTimeUIntComparisons(x: u32) void { } test "const ptr to variable data changes at runtime" { - assertOrPanic(foo_ref.name[0] == 'a'); + expect(foo_ref.name[0] == 'a'); foo_ref.name = "b"; - assertOrPanic(foo_ref.name[0] == 'b'); + expect(foo_ref.name[0] == 'b'); } const Foo = struct { @@ -342,8 +342,8 @@ var foo_contents = Foo{ .name = "a" }; const foo_ref = &foo_contents; test "create global array with for loop" { - assertOrPanic(global_array[5] == 5 * 5); - assertOrPanic(global_array[9] == 9 * 9); + expect(global_array[5] == 5 * 5); + expect(global_array[9] == 9 * 9); } const global_array = x: { @@ -358,7 +358,7 @@ test "compile-time downcast when the bits fit" { comptime { const spartan_count: u16 = 255; const byte = @intCast(u8, spartan_count); - assertOrPanic(byte == 255); + expect(byte == 255); } } @@ -366,44 +366,44 @@ const hi1 = "hi"; const hi2 = hi1; test "const global shares pointer with other same one" { assertEqualPtrs(&hi1[0], &hi2[0]); - comptime assertOrPanic(&hi1[0] == &hi2[0]); + comptime expect(&hi1[0] == &hi2[0]); } fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { - assertOrPanic(ptr1 == ptr2); + expect(ptr1 == ptr2); } test "@setEvalBranchQuota" { comptime { - // 1001 for the loop and then 1 more for the assertOrPanic fn call + // 1001 for the loop and then 1 more for the expect fn call @setEvalBranchQuota(1002); var i = 0; var sum = 0; while (i < 1001) : (i += 1) { sum += i; } - assertOrPanic(sum == 500500); + expect(sum == 500500); } } // TODO test "float literal at compile time not lossy" { -// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0); -// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0); +// TODO expect(16777216.0 + 1.0 == 16777217.0); +// TODO expect(9007199254740992.0 + 1.0 == 9007199254740993.0); // TODO } test "f32 at compile time is lossy" { - assertOrPanic(f32(1 << 24) + 1 == 1 << 24); + expect(f32(1 << 24) + 1 == 1 << 24); } test "f64 at compile time is lossy" { - assertOrPanic(f64(1 << 53) + 1 == 1 << 53); + expect(f64(1 << 53) + 1 == 1 << 53); } test "f128 at compile time is lossy" { - assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); + expect(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); } comptime { - assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192); + expect(f128(1 << 113) == 10384593717069655257060992658440192); } pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { @@ -415,15 +415,15 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { test "string literal used as comptime slice is memoized" { const a = "link"; const b = "link"; - comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); - comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); + comptime expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); + comptime expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); } test "comptime slice of undefined pointer of length 0" { const slice1 = ([*]i32)(undefined)[0..0]; - assertOrPanic(slice1.len == 0); + expect(slice1.len == 0); const slice2 = ([*]i32)(undefined)[100..100]; - assertOrPanic(slice2.len == 0); + expect(slice2.len == 0); } fn copyWithPartialInline(s: []u32, b: []u8) void { @@ -445,16 +445,16 @@ test "binary math operator in partially inlined function" { r.* = @intCast(u8, i + 1); copyWithPartialInline(s[0..], b[0..]); - assertOrPanic(s[0] == 0x1020304); - assertOrPanic(s[1] == 0x5060708); - assertOrPanic(s[2] == 0x90a0b0c); - assertOrPanic(s[3] == 0xd0e0f10); + expect(s[0] == 0x1020304); + expect(s[1] == 0x5060708); + expect(s[2] == 0x90a0b0c); + expect(s[3] == 0xd0e0f10); } test "comptime function with the same args is memoized" { comptime { - assertOrPanic(MakeType(i32) == MakeType(i32)); - assertOrPanic(MakeType(i32) != MakeType(f64)); + expect(MakeType(i32) == MakeType(i32)); + expect(MakeType(i32) != MakeType(f64)); } } @@ -470,7 +470,7 @@ test "comptime function with mutable pointer is not memoized" { const ptr = &x; increment(ptr); increment(ptr); - assertOrPanic(x == 3); + expect(x == 3); } } @@ -496,14 +496,14 @@ fn doesAlotT(comptime T: type, value: usize) T { } test "@setEvalBranchQuota at same scope as generic function call" { - assertOrPanic(doesAlotT(u32, 2) == 2); + expect(doesAlotT(u32, 2) == 2); } test "comptime slice of slice preserves comptime var" { comptime { var buff: [10]u8 = undefined; buff[0..][0..][0] = 1; - assertOrPanic(buff[0..][0..][0] == 1); + expect(buff[0..][0..][0] == 1); } } @@ -512,7 +512,7 @@ test "comptime slice of pointer preserves comptime var" { var buff: [10]u8 = undefined; var a = buff[0..].ptr; a[0..1][0] = 1; - assertOrPanic(buff[0..][0..][0] == 1); + expect(buff[0..][0..][0] == 1); } } @@ -526,9 +526,9 @@ const SingleFieldStruct = struct { test "const ptr to comptime mutable data is not memoized" { comptime { var foo = SingleFieldStruct{ .x = 1 }; - assertOrPanic(foo.read_x() == 1); + expect(foo.read_x() == 1); foo.x = 2; - assertOrPanic(foo.read_x() == 2); + expect(foo.read_x() == 2); } } @@ -537,7 +537,7 @@ test "array concat of slices gives slice" { var a: []const u8 = "aoeu"; var b: []const u8 = "asdf"; const c = a ++ b; - assertOrPanic(std.mem.eql(u8, c, "aoeuasdf")); + expect(std.mem.eql(u8, c, "aoeuasdf")); } } @@ -554,14 +554,14 @@ test "comptime shlWithOverflow" { break :amt amt; }; - assertOrPanic(ct_shifted == rt_shifted); + expect(ct_shifted == rt_shifted); } test "runtime 128 bit integer division" { var a: u128 = 152313999999999991610955792383; var b: u128 = 10000000000000000000; var c = a / b; - assertOrPanic(c == 15231399999); + expect(c == 15231399999); } pub const Info = struct { @@ -574,20 +574,20 @@ test "comptime modification of const struct field" { comptime { var res = diamond_info; res.version = 1; - assertOrPanic(diamond_info.version == 0); - assertOrPanic(res.version == 1); + expect(diamond_info.version == 0); + expect(res.version == 1); } } test "pointer to type" { comptime { var T: type = i32; - assertOrPanic(T == i32); + expect(T == i32); var ptr = &T; - assertOrPanic(@typeOf(ptr) == *type); + expect(@typeOf(ptr) == *type); ptr.* = f32; - assertOrPanic(T == f32); - assertOrPanic(*T == *f32); + expect(T == f32); + expect(*T == *f32); } } @@ -596,17 +596,17 @@ test "slice of type" { var types_array = []type{ i32, f64, type }; for (types_array) |T, i| { switch (i) { - 0 => assertOrPanic(T == i32), - 1 => assertOrPanic(T == f64), - 2 => assertOrPanic(T == type), + 0 => expect(T == i32), + 1 => expect(T == f64), + 2 => expect(T == type), else => unreachable, } } for (types_array[0..]) |T, i| { switch (i) { - 0 => assertOrPanic(T == i32), - 1 => assertOrPanic(T == f64), - 2 => assertOrPanic(T == type), + 0 => expect(T == i32), + 1 => expect(T == f64), + 2 => expect(T == type), else => unreachable, } } @@ -623,7 +623,7 @@ fn wrap(comptime T: type) Wrapper { test "function which returns struct with type field causes implicit comptime" { const ty = wrap(i32).T; - assertOrPanic(ty == i32); + expect(ty == i32); } test "call method with comptime pass-by-non-copying-value self parameter" { @@ -637,12 +637,12 @@ test "call method with comptime pass-by-non-copying-value self parameter" { const s = S{ .a = 2 }; var b = s.b(); - assertOrPanic(b == 2); + expect(b == 2); } test "@tagName of @typeId" { const str = @tagName(@typeId(u8)); - assertOrPanic(std.mem.eql(u8, str, "Int")); + expect(std.mem.eql(u8, str, "Int")); } test "setting backward branch quota just before a generic fn call" { @@ -663,8 +663,8 @@ fn testVarInsideInlineLoop(args: ...) void { comptime var i = 0; inline while (i < args.len) : (i += 1) { const x = args[i]; - if (i == 0) assertOrPanic(x); - if (i == 1) assertOrPanic(x == 42); + if (i == 0) expect(x); + if (i == 1) expect(x == 42); } } @@ -674,7 +674,7 @@ test "inline for with same type but different values" { var a: T = undefined; res += a.len; } - assertOrPanic(res == 5); + expect(res == 5); } test "refer to the type of a generic function" { @@ -688,13 +688,13 @@ fn doNothingWithType(comptime T: type) void {} test "zero extend from u0 to u1" { var zero_u0: u0 = 0; var zero_u1: u1 = zero_u0; - assertOrPanic(zero_u1 == 0); + expect(zero_u1 == 0); } test "bit shift a u1" { var x: u1 = 1; var y = x << 0; - assertOrPanic(y == 1); + expect(y == 1); } test "@bytesToslice on a packed struct" { @@ -704,7 +704,7 @@ test "@bytesToslice on a packed struct" { var b = [1]u8{9}; var f = @bytesToSlice(F, b); - assertOrPanic(f[0].a == 9); + expect(f[0].a == 9); } test "comptime pointer cast array and then slice" { @@ -716,8 +716,8 @@ test "comptime pointer cast array and then slice" { const ptrB: [*]const u8 = &array; const sliceB: []const u8 = ptrB[0..2]; - assertOrPanic(sliceA[1] == 2); - assertOrPanic(sliceB[1] == 2); + expect(sliceA[1] == 2); + expect(sliceB[1] == 2); } test "slice bounds in comptime concatenation" { @@ -726,47 +726,47 @@ test "slice bounds in comptime concatenation" { break :blk b[8..9]; }; const str = "" ++ bs; - assertOrPanic(str.len == 1); - assertOrPanic(std.mem.eql(u8, str, "1")); + expect(str.len == 1); + expect(std.mem.eql(u8, str, "1")); const str2 = bs ++ ""; - assertOrPanic(str2.len == 1); - assertOrPanic(std.mem.eql(u8, str2, "1")); + expect(str2.len == 1); + expect(std.mem.eql(u8, str2, "1")); } test "comptime bitwise operators" { comptime { - assertOrPanic(3 & 1 == 1); - assertOrPanic(3 & -1 == 3); - assertOrPanic(-3 & -1 == -3); - assertOrPanic(3 | -1 == -1); - assertOrPanic(-3 | -1 == -1); - assertOrPanic(3 ^ -1 == -4); - assertOrPanic(-3 ^ -1 == 2); - assertOrPanic(~i8(-1) == 0); - assertOrPanic(~i128(-1) == 0); - assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611); - assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); - assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff); + expect(3 & 1 == 1); + expect(3 & -1 == 3); + expect(-3 & -1 == -3); + expect(3 | -1 == -1); + expect(-3 | -1 == -1); + expect(3 ^ -1 == -4); + expect(-3 ^ -1 == 2); + expect(~i8(-1) == 0); + expect(~i128(-1) == 0); + expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); + expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); + expect(~u128(0) == 0xffffffffffffffffffffffffffffffff); } } test "*align(1) u16 is the same as *align(1:0:2) u16" { comptime { - assertOrPanic(*align(1:0:2) u16 == *align(1) u16); + expect(*align(1:0:2) u16 == *align(1) u16); // TODO add parsing support for this syntax - //assertOrPanic(*align(:0:2) u16 == *u16); + //expect(*align(:0:2) u16 == *u16); } } test "array concatenation forces comptime" { var a = oneItem(3) ++ oneItem(4); - assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 })); + expect(std.mem.eql(i32, a, []i32{ 3, 4 })); } test "array multiplication forces comptime" { var a = oneItem(3) ** scalar(2); - assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 })); + expect(std.mem.eql(i32, a, []i32{ 3, 3 })); } fn oneItem(x: i32) [1]i32 { diff --git a/test/stage1/behavior/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig index ed2487c020..6026a49d12 100644 --- a/test/stage1/behavior/field_parent_ptr.zig +++ b/test/stage1/behavior/field_parent_ptr.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@fieldParentPtr non-first field" { testParentFieldPtr(&foo.c); @@ -25,17 +25,17 @@ const foo = Foo{ }; fn testParentFieldPtr(c: *const i32) void { - assertOrPanic(c == &foo.c); + expect(c == &foo.c); const base = @fieldParentPtr(Foo, "c", c); - assertOrPanic(base == &foo); - assertOrPanic(&base.c == c); + expect(base == &foo); + expect(&base.c == c); } fn testParentFieldPtrFirst(a: *const bool) void { - assertOrPanic(a == &foo.a); + expect(a == &foo.a); const base = @fieldParentPtr(Foo, "a", a); - assertOrPanic(base == &foo); - assertOrPanic(&base.a == a); + expect(base == &foo); + expect(&base.a == a); } diff --git a/test/stage1/behavior/fn.zig b/test/stage1/behavior/fn.zig index 3011bc41d0..3f78c80290 100644 --- a/test/stage1/behavior/fn.zig +++ b/test/stage1/behavior/fn.zig @@ -1,7 +1,7 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "params" { - assertOrPanic(testParamsAdd(22, 11) == 33); + expect(testParamsAdd(22, 11) == 33); } fn testParamsAdd(a: i32, b: i32) i32 { return a + b; @@ -21,32 +21,32 @@ test "void parameters" { fn voidFun(a: i32, b: void, c: i32, d: void) void { const v = b; const vv: void = if (a == 1) v else {}; - assertOrPanic(a + c == 3); + expect(a + c == 3); return vv; } test "mutable local variables" { var zero: i32 = 0; - assertOrPanic(zero == 0); + expect(zero == 0); var i = i32(0); while (i != 3) { i += 1; } - assertOrPanic(i == 3); + expect(i == 3); } test "separate block scopes" { { const no_conflict: i32 = 5; - assertOrPanic(no_conflict == 5); + expect(no_conflict == 5); } const c = x: { const no_conflict = i32(10); break :x no_conflict; }; - assertOrPanic(c == 10); + expect(c == 10); } test "call function with empty string" { @@ -59,7 +59,7 @@ fn @"weird function name"() i32 { return 1234; } test "weird function name" { - assertOrPanic(@"weird function name"() == 1234); + expect(@"weird function name"() == 1234); } test "implicit cast function unreachable return" { @@ -80,7 +80,7 @@ test "function pointers" { fn4, }; for (fns) |f, i| { - assertOrPanic(f() == @intCast(u32, i) + 5); + expect(f() == @intCast(u32, i) + 5); } } fn fn1() u32 { @@ -97,7 +97,7 @@ fn fn4() u32 { } test "inline function call" { - assertOrPanic(@inlineCall(add, 3, 9) == 12); + expect(@inlineCall(add, 3, 9) == 12); } fn add(a: i32, b: i32) i32 { @@ -110,7 +110,7 @@ test "number literal as an argument" { } fn numberLiteralArg(a: var) void { - assertOrPanic(a == 3); + expect(a == 3); } test "assign inline fn to const variable" { @@ -121,7 +121,7 @@ test "assign inline fn to const variable" { inline fn inlineFn() void {} test "pass by non-copying value" { - assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); + expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } const Point = struct { @@ -134,17 +134,17 @@ fn addPointCoords(pt: Point) i32 { } test "pass by non-copying value through var arg" { - assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); + expect(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); } fn addPointCoordsVar(pt: var) i32 { - comptime assertOrPanic(@typeOf(pt) == Point); + comptime expect(@typeOf(pt) == Point); return pt.x + pt.y; } test "pass by non-copying value as method" { var pt = Point2{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords() == 3); + expect(pt.addPointCoords() == 3); } const Point2 = struct { @@ -158,7 +158,7 @@ const Point2 = struct { test "pass by non-copying value as method, which is generic" { var pt = Point3{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords(i32) == 3); + expect(pt.addPointCoords(i32) == 3); } const Point3 = struct { @@ -173,7 +173,7 @@ const Point3 = struct { test "pass by non-copying value as method, at comptime" { comptime { var pt = Point2{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords() == 3); + expect(pt.addPointCoords() == 3); } } @@ -189,7 +189,7 @@ fn outer(y: u32) fn (u32) u32 { test "return inner function which references comptime variable of outer function" { var func = outer(10); - assertOrPanic(func(3) == 7); + expect(func(3) == 7); } test "extern struct with stdcallcc fn pointer" { @@ -203,6 +203,6 @@ test "extern struct with stdcallcc fn pointer" { var s: S = undefined; s.ptr = S.foo; - assertOrPanic(s.ptr() == 1234); + expect(s.ptr() == 1234); } diff --git a/test/stage1/behavior/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig index 0af076d40a..030693ac59 100644 --- a/test/stage1/behavior/fn_in_struct_in_comptime.zig +++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn get_foo() fn (*u8) usize { comptime { @@ -13,5 +13,5 @@ fn get_foo() fn (*u8) usize { test "define a function in an anonymous struct in comptime" { const foo = get_foo(); - assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345); + expect(foo(@intToPtr(*u8, 12345)) == 12345); } diff --git a/test/stage1/behavior/for.zig b/test/stage1/behavior/for.zig index b6d1ef24c4..b10dd14fa4 100644 --- a/test/stage1/behavior/for.zig +++ b/test/stage1/behavior/for.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; test "continue in for loop" { @@ -26,7 +26,7 @@ test "for loop with pointer elem var" { var target: [source.len]u8 = undefined; mem.copy(u8, target[0..], source); mangleString(target[0..]); - assertOrPanic(mem.eql(u8, target, "bcdefgh")); + expect(mem.eql(u8, target, "bcdefgh")); } fn mangleString(s: []u8) void { for (s) |*c| { @@ -68,7 +68,7 @@ test "basic for loop" { buf_index += 1; } - assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result)); + expect(mem.eql(u8, buffer[0..buf_index], expected_result)); } test "break from outer for loop" { @@ -85,7 +85,7 @@ fn testBreakOuter() void { break :outer; } } - assertOrPanic(count == 1); + expect(count == 1); } test "continue outer for loop" { @@ -102,5 +102,5 @@ fn testContinueOuter() void { continue :outer; } } - assertOrPanic(counter == array.len); + expect(counter == array.len); } diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig index a0928634a7..637f9b88ae 100644 --- a/test/stage1/behavior/generics.zig +++ b/test/stage1/behavior/generics.zig @@ -1,9 +1,9 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "simple generic fn" { - assertOrPanic(max(i32, 3, -1) == 3); - assertOrPanic(max(f32, 0.123, 0.456) == 0.456); - assertOrPanic(add(2, 3) == 5); + expect(max(i32, 3, -1) == 3); + expect(max(f32, 0.123, 0.456) == 0.456); + expect(add(2, 3) == 5); } fn max(comptime T: type, a: T, b: T) T { @@ -16,7 +16,7 @@ fn add(comptime a: i32, b: i32) i32 { const the_max = max(u32, 1234, 5678); test "compile time generic eval" { - assertOrPanic(the_max == 5678); + expect(the_max == 5678); } fn gimmeTheBigOne(a: u32, b: u32) u32 { @@ -32,19 +32,19 @@ fn sameButWithFloats(a: f64, b: f64) f64 { } test "fn with comptime args" { - assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678); - assertOrPanic(shouldCallSameInstance(34, 12) == 34); - assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49); + expect(gimmeTheBigOne(1234, 5678) == 5678); + expect(shouldCallSameInstance(34, 12) == 34); + expect(sameButWithFloats(0.43, 0.49) == 0.49); } test "var params" { - assertOrPanic(max_i32(12, 34) == 34); - assertOrPanic(max_f64(1.2, 3.4) == 3.4); + expect(max_i32(12, 34) == 34); + expect(max_f64(1.2, 3.4) == 3.4); } comptime { - assertOrPanic(max_i32(12, 34) == 34); - assertOrPanic(max_f64(1.2, 3.4) == 3.4); + expect(max_i32(12, 34) == 34); + expect(max_f64(1.2, 3.4) == 3.4); } fn max_var(a: var, b: var) @typeOf(a + b) { @@ -76,8 +76,8 @@ test "function with return type type" { var list2: List(i32) = undefined; list.length = 10; list2.length = 10; - assertOrPanic(list.prealloc_items.len == 8); - assertOrPanic(list2.prealloc_items.len == 8); + expect(list.prealloc_items.len == 8); + expect(list2.prealloc_items.len == 8); } test "generic struct" { @@ -89,9 +89,9 @@ test "generic struct" { .value = true, .next = null, }; - assertOrPanic(a1.value == 13); - assertOrPanic(a1.value == a1.getVal()); - assertOrPanic(b1.getVal()); + expect(a1.value == 13); + expect(a1.value == a1.getVal()); + expect(b1.getVal()); } fn GenNode(comptime T: type) type { return struct { @@ -104,7 +104,7 @@ fn GenNode(comptime T: type) type { } test "const decls in struct" { - assertOrPanic(GenericDataThing(3).count_plus_one == 4); + expect(GenericDataThing(3).count_plus_one == 4); } fn GenericDataThing(comptime count: isize) type { return struct { @@ -113,15 +113,15 @@ fn GenericDataThing(comptime count: isize) type { } test "use generic param in generic param" { - assertOrPanic(aGenericFn(i32, 3, 4) == 7); + expect(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(comptime T: type, comptime a: T, b: T) T { return a + b; } test "generic fn with implicit cast" { - assertOrPanic(getFirstByte(u8, []u8{13}) == 13); - assertOrPanic(getFirstByte(u16, []u16{ + expect(getFirstByte(u8, []u8{13}) == 13); + expect(getFirstByte(u16, []u16{ 0, 13, }) == 0); @@ -146,6 +146,6 @@ fn foo2(arg: var) bool { } test "array of generic fns" { - assertOrPanic(foos[0](true)); - assertOrPanic(!foos[1](true)); + expect(foos[0](true)); + expect(!foos[1](true)); } diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig index 58d1b8fd73..a61b9dcfb4 100644 --- a/test/stage1/behavior/if.zig +++ b/test/stage1/behavior/if.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "if statements" { shouldBeEqual(1, 1); @@ -24,7 +24,7 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void { } test "else if expression" { - assertOrPanic(elseIfExpressionF(1) == 1); + expect(elseIfExpressionF(1) == 1); } fn elseIfExpressionF(c: u8) u8 { if (c == 0) { diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig index 736e4c219d..9a8c6848e2 100644 --- a/test/stage1/behavior/import.zig +++ b/test/stage1/behavior/import.zig @@ -1,10 +1,10 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const a_namespace = @import("import/a_namespace.zig"); test "call fn via namespace lookup" { - assertOrPanic(a_namespace.foo() == 1234); + expect(a_namespace.foo() == 1234); } test "importing the same thing gives the same import" { - assertOrPanic(@import("std") == @import("std")); + expect(@import("std") == @import("std")); } diff --git a/test/stage1/behavior/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig index d062311b2e..77a3dfd221 100644 --- a/test/stage1/behavior/incomplete_struct_param_tld.zig +++ b/test/stage1/behavior/incomplete_struct_param_tld.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const A = struct { b: B, @@ -26,5 +26,5 @@ test "incomplete struct param top level declaration" { .c = C{ .x = 13 }, }, }; - assertOrPanic(foo(a) == 13); + expect(foo(a) == 13); } diff --git a/test/stage1/behavior/inttoptr.zig b/test/stage1/behavior/inttoptr.zig index bf657fc86a..b1780f93d6 100644 --- a/test/stage1/behavior/inttoptr.zig +++ b/test/stage1/behavior/inttoptr.zig @@ -1,6 +1,6 @@ const builtin = @import("builtin"); const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "casting random address to function pointer" { randomAddressToFunction(); diff --git a/test/stage1/behavior/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig index bc61e11df7..821079df79 100644 --- a/test/stage1/behavior/ir_block_deps.zig +++ b/test/stage1/behavior/ir_block_deps.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn foo(id: u64) !i32 { return switch (id) { @@ -16,6 +16,6 @@ fn getErrInt() anyerror!i32 { } test "ir block deps" { - assertOrPanic((foo(1) catch unreachable) == 0); - assertOrPanic((foo(2) catch unreachable) == 0); + expect((foo(1) catch unreachable) == 0); + expect((foo(2) catch unreachable) == 0); } diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index 9d6a5a4997..0b88cc4497 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -8,57 +8,57 @@ test "division" { comptime testDivision(); } fn testDivision() void { - assertOrPanic(div(u32, 13, 3) == 4); - assertOrPanic(div(f16, 1.0, 2.0) == 0.5); - assertOrPanic(div(f32, 1.0, 2.0) == 0.5); + expect(div(u32, 13, 3) == 4); + expect(div(f16, 1.0, 2.0) == 0.5); + expect(div(f32, 1.0, 2.0) == 0.5); - assertOrPanic(divExact(u32, 55, 11) == 5); - assertOrPanic(divExact(i32, -55, 11) == -5); - assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0); - assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0); - assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0); - assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0); + expect(divExact(u32, 55, 11) == 5); + expect(divExact(i32, -55, 11) == -5); + expect(divExact(f16, 55.0, 11.0) == 5.0); + expect(divExact(f16, -55.0, 11.0) == -5.0); + expect(divExact(f32, 55.0, 11.0) == 5.0); + expect(divExact(f32, -55.0, 11.0) == -5.0); - assertOrPanic(divFloor(i32, 5, 3) == 1); - assertOrPanic(divFloor(i32, -5, 3) == -2); - assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0); - assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0); - assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0); - assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0); - assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000); - assertOrPanic(divFloor(i32, 0, -0x80000000) == 0); - assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2); - assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000); + expect(divFloor(i32, 5, 3) == 1); + expect(divFloor(i32, -5, 3) == -2); + expect(divFloor(f16, 5.0, 3.0) == 1.0); + expect(divFloor(f16, -5.0, 3.0) == -2.0); + expect(divFloor(f32, 5.0, 3.0) == 1.0); + expect(divFloor(f32, -5.0, 3.0) == -2.0); + expect(divFloor(i32, -0x80000000, -2) == 0x40000000); + expect(divFloor(i32, 0, -0x80000000) == 0); + expect(divFloor(i32, -0x40000001, 0x40000000) == -2); + expect(divFloor(i32, -0x80000000, 1) == -0x80000000); - assertOrPanic(divTrunc(i32, 5, 3) == 1); - assertOrPanic(divTrunc(i32, -5, 3) == -1); - assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0); - assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0); - assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0); + expect(divTrunc(i32, 5, 3) == 1); + expect(divTrunc(i32, -5, 3) == -1); + expect(divTrunc(f16, 5.0, 3.0) == 1.0); + expect(divTrunc(f16, -5.0, 3.0) == -1.0); + expect(divTrunc(f32, 5.0, 3.0) == 1.0); + expect(divTrunc(f32, -5.0, 3.0) == -1.0); + expect(divTrunc(f64, 5.0, 3.0) == 1.0); + expect(divTrunc(f64, -5.0, 3.0) == -1.0); comptime { - assertOrPanic( + expect( 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, ); - assertOrPanic( + expect( @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, ); - assertOrPanic( + expect( 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, ); - assertOrPanic( + expect( @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, ); - assertOrPanic( + expect( @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, ); - assertOrPanic( + expect( @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, ); - assertOrPanic( + expect( 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, ); } @@ -78,9 +78,9 @@ fn divTrunc(comptime T: type, a: T, b: T) T { test "@addWithOverflow" { var result: u8 = undefined; - assertOrPanic(@addWithOverflow(u8, 250, 100, &result)); - assertOrPanic(!@addWithOverflow(u8, 100, 150, &result)); - assertOrPanic(result == 250); + expect(@addWithOverflow(u8, 250, 100, &result)); + expect(!@addWithOverflow(u8, 100, 150, &result)); + expect(result == 250); } // TODO test mulWithOverflow @@ -88,9 +88,9 @@ test "@addWithOverflow" { test "@shlWithOverflow" { var result: u16 = undefined; - assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - assertOrPanic(result == 0b1011111111111100); + expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); + expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); + expect(result == 0b1011111111111100); } test "@clz" { @@ -99,11 +99,11 @@ test "@clz" { } fn testClz() void { - assertOrPanic(clz(u8(0b00001010)) == 4); - assertOrPanic(clz(u8(0b10001010)) == 0); - assertOrPanic(clz(u8(0b00000000)) == 8); - assertOrPanic(clz(u128(0xffffffffffffffff)) == 64); - assertOrPanic(clz(u128(0x10000000000000000)) == 63); + expect(clz(u8(0b00001010)) == 4); + expect(clz(u8(0b10001010)) == 0); + expect(clz(u8(0b00000000)) == 8); + expect(clz(u128(0xffffffffffffffff)) == 64); + expect(clz(u128(0x10000000000000000)) == 63); } fn clz(x: var) usize { @@ -116,9 +116,9 @@ test "@ctz" { } fn testCtz() void { - assertOrPanic(ctz(u8(0b10100000)) == 5); - assertOrPanic(ctz(u8(0b10001010)) == 1); - assertOrPanic(ctz(u8(0b00000000)) == 8); + expect(ctz(u8(0b10100000)) == 5); + expect(ctz(u8(0b10001010)) == 1); + expect(ctz(u8(0b00000000)) == 8); } fn ctz(x: var) usize { @@ -128,27 +128,27 @@ fn ctz(x: var) usize { test "assignment operators" { var i: u32 = 0; i += 5; - assertOrPanic(i == 5); + expect(i == 5); i -= 2; - assertOrPanic(i == 3); + expect(i == 3); i *= 20; - assertOrPanic(i == 60); + expect(i == 60); i /= 3; - assertOrPanic(i == 20); + expect(i == 20); i %= 11; - assertOrPanic(i == 9); + expect(i == 9); i <<= 1; - assertOrPanic(i == 18); + expect(i == 18); i >>= 2; - assertOrPanic(i == 4); + expect(i == 4); i = 6; i &= 5; - assertOrPanic(i == 4); + expect(i == 4); i ^= 6; - assertOrPanic(i == 2); + expect(i == 2); i = 6; i |= 3; - assertOrPanic(i == 7); + expect(i == 7); } test "three expr in a row" { @@ -170,14 +170,14 @@ fn testThreeExprInARow(f: bool, t: bool) void { assertFalse(i32(7) != --(i32(7))); } fn assertFalse(b: bool) void { - assertOrPanic(!b); + expect(!b); } test "const number literal" { const one = 1; const eleven = ten + one; - assertOrPanic(eleven == 11); + expect(eleven == 11); } const ten = 10; @@ -187,9 +187,9 @@ test "unsigned wrapping" { } fn testUnsignedWrappingEval(x: u32) void { const zero = x +% 1; - assertOrPanic(zero == 0); + expect(zero == 0); const orig = zero -% 1; - assertOrPanic(orig == maxInt(u32)); + expect(orig == maxInt(u32)); } test "signed wrapping" { @@ -198,9 +198,9 @@ test "signed wrapping" { } fn testSignedWrappingEval(x: i32) void { const min_val = x +% 1; - assertOrPanic(min_val == minInt(i32)); + expect(min_val == minInt(i32)); const max_val = min_val -% 1; - assertOrPanic(max_val == maxInt(i32)); + expect(max_val == maxInt(i32)); } test "negation wrapping" { @@ -208,9 +208,9 @@ test "negation wrapping" { comptime testNegationWrappingEval(minInt(i16)); } fn testNegationWrappingEval(x: i16) void { - assertOrPanic(x == -32768); + expect(x == -32768); const neg = -%x; - assertOrPanic(neg == -32768); + expect(neg == -32768); } test "unsigned 64-bit division" { @@ -219,8 +219,8 @@ test "unsigned 64-bit division" { } fn test_u64_div() void { const result = divWithResult(1152921504606846976, 34359738365); - assertOrPanic(result.quotient == 33554432); - assertOrPanic(result.remainder == 100663296); + expect(result.quotient == 33554432); + expect(result.remainder == 100663296); } fn divWithResult(a: u64, b: u64) DivResult { return DivResult{ @@ -234,36 +234,36 @@ const DivResult = struct { }; test "binary not" { - assertOrPanic(comptime x: { + expect(comptime x: { break :x ~u16(0b1010101010101010) == 0b0101010101010101; }); - assertOrPanic(comptime x: { + expect(comptime x: { break :x ~u64(2147483647) == 18446744071562067968; }); testBinaryNot(0b1010101010101010); } fn testBinaryNot(x: u16) void { - assertOrPanic(~x == 0b0101010101010101); + expect(~x == 0b0101010101010101); } test "small int addition" { var x: @IntType(false, 2) = 0; - assertOrPanic(x == 0); + expect(x == 0); x += 1; - assertOrPanic(x == 1); + expect(x == 1); x += 1; - assertOrPanic(x == 2); + expect(x == 2); x += 1; - assertOrPanic(x == 3); + expect(x == 3); var result: @typeOf(x) = 3; - assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result)); + expect(@addWithOverflow(@typeOf(x), x, 1, &result)); - assertOrPanic(result == 0); + expect(result == 0); } test "float equality" { @@ -276,20 +276,20 @@ test "float equality" { fn testFloatEqualityImpl(x: f64, y: f64) void { const y2 = x + 1.0; - assertOrPanic(y == y2); + expect(y == y2); } test "allow signed integer division/remainder when values are comptime known and positive or exact" { - assertOrPanic(5 / 3 == 1); - assertOrPanic(-5 / -3 == 1); - assertOrPanic(-6 / 3 == -2); + expect(5 / 3 == 1); + expect(-5 / -3 == 1); + expect(-6 / 3 == -2); - assertOrPanic(5 % 3 == 2); - assertOrPanic(-6 % 3 == 0); + expect(5 % 3 == 2); + expect(-6 % 3 == 0); } test "hex float literal parsing" { - comptime assertOrPanic(0x1.0 == 1.0); + comptime expect(0x1.0 == 1.0); } test "quad hex float literal parsing in range" { @@ -304,7 +304,7 @@ test "quad hex float literal parsing accurate" { // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. const expected: u128 = 0x3fff1111222233334444555566667777; - assertOrPanic(@bitCast(u128, a) == expected); + expect(@bitCast(u128, a) == expected); } test "hex float literal within range" { @@ -319,7 +319,7 @@ test "truncating shift left" { } fn testShlTrunc(x: u16) void { const shifted = x << 1; - assertOrPanic(shifted == 65534); + expect(shifted == 65534); } test "truncating shift right" { @@ -328,7 +328,7 @@ test "truncating shift right" { } fn testShrTrunc(x: u16) void { const shifted = x >> 1; - assertOrPanic(shifted == 32767); + expect(shifted == 32767); } test "exact shift left" { @@ -337,7 +337,7 @@ test "exact shift left" { } fn testShlExact(x: u8) void { const shifted = @shlExact(x, 2); - assertOrPanic(shifted == 0b11010100); + expect(shifted == 0b11010100); } test "exact shift right" { @@ -346,22 +346,22 @@ test "exact shift right" { } fn testShrExact(x: u8) void { const shifted = @shrExact(x, 2); - assertOrPanic(shifted == 0b00101101); + expect(shifted == 0b00101101); } test "comptime_int addition" { comptime { - assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); - assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); + expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); + expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); } } test "comptime_int multiplication" { comptime { - assertOrPanic( + expect( 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, ); - assertOrPanic( + expect( 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, ); } @@ -369,7 +369,7 @@ test "comptime_int multiplication" { test "comptime_int shifting" { comptime { - assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000); + expect((u128(1) << 127) == 0x80000000000000000000000000000000); } } @@ -377,16 +377,16 @@ test "comptime_int multi-limb shift and mask" { comptime { var a = 0xefffffffa0000001eeeeeeefaaaaaaab; - assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab); + expect(u32(a & 0xffffffff) == 0xaaaaaaab); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef); + expect(u32(a & 0xffffffff) == 0xeeeeeeef); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xa0000001); + expect(u32(a & 0xffffffff) == 0xa0000001); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xefffffff); + expect(u32(a & 0xffffffff) == 0xefffffff); a >>= 32; - assertOrPanic(a == 0); + expect(a == 0); } } @@ -394,7 +394,7 @@ test "comptime_int multi-limb partial shift right" { comptime { var a = 0x1ffffffffeeeeeeee; a >>= 16; - assertOrPanic(a == 0x1ffffffffeeee); + expect(a == 0x1ffffffffeeee); } } @@ -404,23 +404,23 @@ test "xor" { } fn test_xor() void { - assertOrPanic(0xFF ^ 0x00 == 0xFF); - assertOrPanic(0xF0 ^ 0x0F == 0xFF); - assertOrPanic(0xFF ^ 0xF0 == 0x0F); - assertOrPanic(0xFF ^ 0x0F == 0xF0); - assertOrPanic(0xFF ^ 0xFF == 0x00); + expect(0xFF ^ 0x00 == 0xFF); + expect(0xF0 ^ 0x0F == 0xFF); + expect(0xFF ^ 0xF0 == 0x0F); + expect(0xFF ^ 0x0F == 0xF0); + expect(0xFF ^ 0xFF == 0x00); } test "comptime_int xor" { comptime { - assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); - assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); - assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); - assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); - assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); + expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); + expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); + expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); + expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); + expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); } } @@ -434,23 +434,23 @@ fn make_f128(x: f128) f128 { } fn test_f128() void { - assertOrPanic(@sizeOf(f128) == 16); - assertOrPanic(make_f128(1.0) == 1.0); - assertOrPanic(make_f128(1.0) != 1.1); - assertOrPanic(make_f128(1.0) > 0.9); - assertOrPanic(make_f128(1.0) >= 0.9); - assertOrPanic(make_f128(1.0) >= 1.0); + expect(@sizeOf(f128) == 16); + expect(make_f128(1.0) == 1.0); + expect(make_f128(1.0) != 1.1); + expect(make_f128(1.0) > 0.9); + expect(make_f128(1.0) >= 0.9); + expect(make_f128(1.0) >= 1.0); should_not_be_zero(1.0); } fn should_not_be_zero(x: f128) void { - assertOrPanic(x != 0.0); + expect(x != 0.0); } test "comptime float rem int" { comptime { var x = f32(1) % 2; - assertOrPanic(x == 1.0); + expect(x == 1.0); } } @@ -465,8 +465,8 @@ test "remainder division" { } fn remdiv(comptime T: type) void { - assertOrPanic(T(1) == T(1) % T(2)); - assertOrPanic(T(1) == T(7) % T(3)); + expect(T(1) == T(1) % T(2)); + expect(T(1) == T(7) % T(3)); } test "@sqrt" { @@ -480,19 +480,19 @@ test "@sqrt" { const x = 14.0; const y = x * x; const z = @sqrt(@typeOf(y), y); - comptime assertOrPanic(z == x); + comptime expect(z == x); } fn testSqrt(comptime T: type, x: T) void { - assertOrPanic(@sqrt(T, x * x) == x); + expect(@sqrt(T, x * x) == x); } test "comptime_int param and return" { const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); - assertOrPanic(a == 137114567242441932203689521744947848950); + expect(a == 137114567242441932203689521744947848950); const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); - assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380); + expect(b == 985095453608931032642182098849559179469148836107390954364380); } fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 3cc8e5f31e..91cab78bc7 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; const cstr = std.cstr; const builtin = @import("builtin"); @@ -26,38 +26,38 @@ test "call disabled extern fn" { } test "@IntType builtin" { - assertOrPanic(@IntType(true, 8) == i8); - assertOrPanic(@IntType(true, 16) == i16); - assertOrPanic(@IntType(true, 32) == i32); - assertOrPanic(@IntType(true, 64) == i64); + expect(@IntType(true, 8) == i8); + expect(@IntType(true, 16) == i16); + expect(@IntType(true, 32) == i32); + expect(@IntType(true, 64) == i64); - assertOrPanic(@IntType(false, 8) == u8); - assertOrPanic(@IntType(false, 16) == u16); - assertOrPanic(@IntType(false, 32) == u32); - assertOrPanic(@IntType(false, 64) == u64); + expect(@IntType(false, 8) == u8); + expect(@IntType(false, 16) == u16); + expect(@IntType(false, 32) == u32); + expect(@IntType(false, 64) == u64); - assertOrPanic(i8.bit_count == 8); - assertOrPanic(i16.bit_count == 16); - assertOrPanic(i32.bit_count == 32); - assertOrPanic(i64.bit_count == 64); + expect(i8.bit_count == 8); + expect(i16.bit_count == 16); + expect(i32.bit_count == 32); + expect(i64.bit_count == 64); - assertOrPanic(i8.is_signed); - assertOrPanic(i16.is_signed); - assertOrPanic(i32.is_signed); - assertOrPanic(i64.is_signed); - assertOrPanic(isize.is_signed); + expect(i8.is_signed); + expect(i16.is_signed); + expect(i32.is_signed); + expect(i64.is_signed); + expect(isize.is_signed); - assertOrPanic(!u8.is_signed); - assertOrPanic(!u16.is_signed); - assertOrPanic(!u32.is_signed); - assertOrPanic(!u64.is_signed); - assertOrPanic(!usize.is_signed); + expect(!u8.is_signed); + expect(!u16.is_signed); + expect(!u32.is_signed); + expect(!u64.is_signed); + expect(!usize.is_signed); } test "floating point primitive bit counts" { - assertOrPanic(f16.bit_count == 16); - assertOrPanic(f32.bit_count == 32); - assertOrPanic(f64.bit_count == 64); + expect(f16.bit_count == 16); + expect(f32.bit_count == 32); + expect(f64.bit_count == 64); } test "short circuit" { @@ -72,7 +72,7 @@ fn testShortCircuit(f: bool, t: bool) void { var hit_4 = f; if (t or x: { - assertOrPanic(f); + expect(f); break :x f; }) { hit_1 = t; @@ -81,31 +81,31 @@ fn testShortCircuit(f: bool, t: bool) void { hit_2 = t; break :x f; }) { - assertOrPanic(f); + expect(f); } if (t and x: { hit_3 = t; break :x f; }) { - assertOrPanic(f); + expect(f); } if (f and x: { - assertOrPanic(f); + expect(f); break :x f; }) { - assertOrPanic(f); + expect(f); } else { hit_4 = t; } - assertOrPanic(hit_1); - assertOrPanic(hit_2); - assertOrPanic(hit_3); - assertOrPanic(hit_4); + expect(hit_1); + expect(hit_2); + expect(hit_3); + expect(hit_4); } test "truncate" { - assertOrPanic(testTruncate(0x10fd) == 0xfd); + expect(testTruncate(0x10fd) == 0xfd); } fn testTruncate(x: u32) u8 { return @truncate(u8, x); @@ -116,16 +116,16 @@ fn first4KeysOfHomeRow() []const u8 { } test "return string from function" { - assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); + expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); } const g1: i32 = 1233 + 1; var g2: i32 = 0; test "global variables" { - assertOrPanic(g2 == 0); + expect(g2 == 0); g2 = g1; - assertOrPanic(g2 == 1234); + expect(g2 == 1234); } test "memcpy and memset intrinsics" { @@ -142,7 +142,7 @@ test "builtin static eval" { const x: i32 = comptime x: { break :x 1 + 2 + 3; }; - assertOrPanic(x == comptime 6); + expect(x == comptime 6); } test "slicing" { @@ -163,7 +163,7 @@ test "slicing" { test "constant equal function pointers" { const alias = emptyFn; - assertOrPanic(comptime x: { + expect(comptime x: { break :x emptyFn == alias; }); } @@ -171,25 +171,25 @@ test "constant equal function pointers" { fn emptyFn() void {} test "hex escape" { - assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); + expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); } test "string concatenation" { - assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); + expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); } test "array mult operator" { - assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab")); + expect(mem.eql(u8, "ab" ** 5, "ababababab")); } test "string escapes" { - assertOrPanic(mem.eql(u8, "\"", "\x22")); - assertOrPanic(mem.eql(u8, "\'", "\x27")); - assertOrPanic(mem.eql(u8, "\n", "\x0a")); - assertOrPanic(mem.eql(u8, "\r", "\x0d")); - assertOrPanic(mem.eql(u8, "\t", "\x09")); - assertOrPanic(mem.eql(u8, "\\", "\x5c")); - assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); + expect(mem.eql(u8, "\"", "\x22")); + expect(mem.eql(u8, "\'", "\x27")); + expect(mem.eql(u8, "\n", "\x0a")); + expect(mem.eql(u8, "\r", "\x0d")); + expect(mem.eql(u8, "\t", "\x09")); + expect(mem.eql(u8, "\\", "\x5c")); + expect(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); } test "multiline string" { @@ -199,7 +199,7 @@ test "multiline string" { \\three ; const s2 = "one\ntwo)\nthree"; - assertOrPanic(mem.eql(u8, s1, s2)); + expect(mem.eql(u8, s1, s2)); } test "multiline C string" { @@ -209,11 +209,11 @@ test "multiline C string" { c\\three ; const s2 = c"one\ntwo)\nthree"; - assertOrPanic(cstr.cmp(s1, s2) == 0); + expect(cstr.cmp(s1, s2) == 0); } test "type equality" { - assertOrPanic(*const u8 != *u8); + expect(*const u8 != *u8); } const global_a: i32 = 1234; @@ -221,7 +221,7 @@ const global_b: *const i32 = &global_a; const global_c: *const f32 = @ptrCast(*const f32, global_b); test "compile time global reinterpret" { const d = @ptrCast(*const i32, global_c); - assertOrPanic(d.* == 1234); + expect(d.* == 1234); } test "explicit cast maybe pointers" { @@ -247,8 +247,8 @@ test "cast undefined" { fn testCastUndefined(x: []const u8) void {} test "cast small unsigned to larger signed" { - assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200)); - assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); + expect(castSmallUnsignedToLargerSigned1(200) == i16(200)); + expect(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); } fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; @@ -258,7 +258,7 @@ fn castSmallUnsignedToLargerSigned2(x: u16) i64 { } test "implicit cast after unreachable" { - assertOrPanic(outer() == 1234); + expect(outer() == 1234); } fn inner() i32 { return 1234; @@ -273,13 +273,13 @@ test "pointer dereferencing" { y.* += 1; - assertOrPanic(x == 4); - assertOrPanic(y.* == 4); + expect(x == 4); + expect(y.* == 4); } test "call result of if else expression" { - assertOrPanic(mem.eql(u8, f2(true), "a")); - assertOrPanic(mem.eql(u8, f2(false), "b")); + expect(mem.eql(u8, f2(true), "a")); + expect(mem.eql(u8, f2(false), "b")); } fn f2(x: bool) []const u8 { return (if (x) fA else fB)(); @@ -321,8 +321,8 @@ const test3_bar = Test3Foo{ .Two = 13 }; fn test3_1(f: Test3Foo) void { switch (f) { Test3Foo.Three => |pt| { - assertOrPanic(pt.x == 3); - assertOrPanic(pt.y == 4); + expect(pt.x == 3); + expect(pt.y == 4); }, else => unreachable, } @@ -330,14 +330,14 @@ fn test3_1(f: Test3Foo) void { fn test3_2(f: Test3Foo) void { switch (f) { Test3Foo.Two => |x| { - assertOrPanic(x == 13); + expect(x == 13); }, else => unreachable, } } test "character literals" { - assertOrPanic('\'' == single_quote); + expect('\'' == single_quote); } const single_quote = '\''; @@ -346,13 +346,13 @@ test "take address of parameter" { } fn testTakeAddressOfParameter(f: f32) void { const f_ptr = &f; - assertOrPanic(f_ptr.* == 12.34); + expect(f_ptr.* == 12.34); } test "pointer comparison" { const a = ([]const u8)("a"); const b = &a; - assertOrPanic(ptrEql(b, b)); + expect(ptrEql(b, b)); } fn ptrEql(a: *const []const u8, b: *const []const u8) bool { return a == b; @@ -367,31 +367,31 @@ test "C string concatenation" { { var i: u32 = 0; while (i < len_with_null) : (i += 1) { - assertOrPanic(a[i] == b[i]); + expect(a[i] == b[i]); } } - assertOrPanic(a[len] == 0); - assertOrPanic(b[len] == 0); + expect(a[len] == 0); + expect(b[len] == 0); } test "cast slice to u8 slice" { - assertOrPanic(@sizeOf(i32) == 4); + expect(@sizeOf(i32) == 4); var big_thing_array = []i32{ 1, 2, 3, 4 }; const big_thing_slice: []i32 = big_thing_array[0..]; const bytes = @sliceToBytes(big_thing_slice); - assertOrPanic(bytes.len == 4 * 4); + expect(bytes.len == 4 * 4); bytes[4] = 0; bytes[5] = 0; bytes[6] = 0; bytes[7] = 0; - assertOrPanic(big_thing_slice[1] == 0); + expect(big_thing_slice[1] == 0); const big_thing_again = @bytesToSlice(i32, bytes); - assertOrPanic(big_thing_again[2] == 3); + expect(big_thing_again[2] == 3); big_thing_again[2] = -1; - assertOrPanic(bytes[8] == maxInt(u8)); - assertOrPanic(bytes[9] == maxInt(u8)); - assertOrPanic(bytes[10] == maxInt(u8)); - assertOrPanic(bytes[11] == maxInt(u8)); + expect(bytes[8] == maxInt(u8)); + expect(bytes[9] == maxInt(u8)); + expect(bytes[10] == maxInt(u8)); + expect(bytes[11] == maxInt(u8)); } test "pointer to void return type" { @@ -408,7 +408,7 @@ fn testPointerToVoidReturnType2() *const void { test "non const ptr to aliased type" { const int = i32; - assertOrPanic(?*int == ?*i32); + expect(?*int == ?*i32); } test "array 2D const double ptr" { @@ -421,8 +421,8 @@ test "array 2D const double ptr" { fn testArray2DConstDoublePtr(ptr: *const f32) void { const ptr2 = @ptrCast([*]const f32, ptr); - assertOrPanic(ptr2[0] == 1.0); - assertOrPanic(ptr2[1] == 2.0); + expect(ptr2[0] == 1.0); + expect(ptr2[1] == 2.0); } const Tid = builtin.TypeId; @@ -444,32 +444,32 @@ const AUnion = union { test "@typeId" { comptime { - assertOrPanic(@typeId(type) == Tid.Type); - assertOrPanic(@typeId(void) == Tid.Void); - assertOrPanic(@typeId(bool) == Tid.Bool); - assertOrPanic(@typeId(noreturn) == Tid.NoReturn); - assertOrPanic(@typeId(i8) == Tid.Int); - assertOrPanic(@typeId(u8) == Tid.Int); - assertOrPanic(@typeId(i64) == Tid.Int); - assertOrPanic(@typeId(u64) == Tid.Int); - assertOrPanic(@typeId(f32) == Tid.Float); - assertOrPanic(@typeId(f64) == Tid.Float); - assertOrPanic(@typeId(*f32) == Tid.Pointer); - assertOrPanic(@typeId([2]u8) == Tid.Array); - assertOrPanic(@typeId(AStruct) == Tid.Struct); - assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt); - assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); - assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined); - assertOrPanic(@typeId(@typeOf(null)) == Tid.Null); - assertOrPanic(@typeId(?i32) == Tid.Optional); - assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion); - assertOrPanic(@typeId(anyerror) == Tid.ErrorSet); - assertOrPanic(@typeId(AnEnum) == Tid.Enum); - assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); - assertOrPanic(@typeId(AUnionEnum) == Tid.Union); - assertOrPanic(@typeId(AUnion) == Tid.Union); - assertOrPanic(@typeId(fn () void) == Tid.Fn); - assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace); + expect(@typeId(type) == Tid.Type); + expect(@typeId(void) == Tid.Void); + expect(@typeId(bool) == Tid.Bool); + expect(@typeId(noreturn) == Tid.NoReturn); + expect(@typeId(i8) == Tid.Int); + expect(@typeId(u8) == Tid.Int); + expect(@typeId(i64) == Tid.Int); + expect(@typeId(u64) == Tid.Int); + expect(@typeId(f32) == Tid.Float); + expect(@typeId(f64) == Tid.Float); + expect(@typeId(*f32) == Tid.Pointer); + expect(@typeId([2]u8) == Tid.Array); + expect(@typeId(AStruct) == Tid.Struct); + expect(@typeId(@typeOf(1)) == Tid.ComptimeInt); + expect(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); + expect(@typeId(@typeOf(undefined)) == Tid.Undefined); + expect(@typeId(@typeOf(null)) == Tid.Null); + expect(@typeId(?i32) == Tid.Optional); + expect(@typeId(anyerror!i32) == Tid.ErrorUnion); + expect(@typeId(anyerror) == Tid.ErrorSet); + expect(@typeId(AnEnum) == Tid.Enum); + expect(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); + expect(@typeId(AUnionEnum) == Tid.Union); + expect(@typeId(AUnion) == Tid.Union); + expect(@typeId(fn () void) == Tid.Fn); + expect(@typeId(@typeOf(builtin)) == Tid.Namespace); // TODO bound fn // TODO arg tuple // TODO opaque @@ -485,13 +485,13 @@ test "@typeName" { Unused, }; comptime { - assertOrPanic(mem.eql(u8, @typeName(i64), "i64")); - assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize")); + expect(mem.eql(u8, @typeName(i64), "i64")); + expect(mem.eql(u8, @typeName(*usize), "*usize")); // https://github.com/ziglang/zig/issues/675 - assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); - assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct")); - assertOrPanic(mem.eql(u8, @typeName(Union), "Union")); - assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum")); + expect(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); + expect(mem.eql(u8, @typeName(Struct), "Struct")); + expect(mem.eql(u8, @typeName(Union), "Union")); + expect(mem.eql(u8, @typeName(Enum), "Enum")); } } @@ -501,14 +501,14 @@ fn TypeFromFn(comptime T: type) type { test "double implicit cast in same expression" { var x = i32(u16(nine())); - assertOrPanic(x == 9); + expect(x == 9); } fn nine() u8 { return 9; } test "global variable initialized to global variable array element" { - assertOrPanic(global_ptr == &gdt[0]); + expect(global_ptr == &gdt[0]); } const GDTEntry = struct { field: i32, @@ -529,9 +529,9 @@ export fn writeToVRam() void { const OpaqueA = @OpaqueType(); const OpaqueB = @OpaqueType(); test "@OpaqueType" { - assertOrPanic(*OpaqueA != *OpaqueB); - assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); - assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); + expect(*OpaqueA != *OpaqueB); + expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); + expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); } test "variable is allowed to be a pointer to an opaque type" { @@ -571,7 +571,7 @@ fn fnThatClosesOverLocalConst() type { test "function closes over local const" { const x = fnThatClosesOverLocalConst().g(); - assertOrPanic(x == 1); + expect(x == 1); } test "cold function" { @@ -608,21 +608,21 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: Pack test "slicing zero length array" { const s1 = ""[0..]; const s2 = ([]u32{})[0..]; - assertOrPanic(s1.len == 0); - assertOrPanic(s2.len == 0); - assertOrPanic(mem.eql(u8, s1, "")); - assertOrPanic(mem.eql(u32, s2, []u32{})); + expect(s1.len == 0); + expect(s2.len == 0); + expect(mem.eql(u8, s1, "")); + expect(mem.eql(u32, s2, []u32{})); } const addr1 = @ptrCast(*const u8, emptyFn); test "comptime cast fn to ptr" { const addr2 = @ptrCast(*const u8, emptyFn); - comptime assertOrPanic(addr1 == addr2); + comptime expect(addr1 == addr2); } test "equality compare fn ptrs" { var a = emptyFn; - assertOrPanic(a == a); + expect(a == a); } test "self reference through fn ptr field" { @@ -637,26 +637,26 @@ test "self reference through fn ptr field" { }; var a: S.A = undefined; a.f = S.foo; - assertOrPanic(a.f(a) == 12); + expect(a.f(a) == 12); } test "volatile load and store" { var number: i32 = 1234; const ptr = (*volatile i32)(&number); ptr.* += 1; - assertOrPanic(ptr.* == 1235); + expect(ptr.* == 1235); } test "slice string literal has type []const u8" { comptime { - assertOrPanic(@typeOf("aoeu"[0..]) == []const u8); + expect(@typeOf("aoeu"[0..]) == []const u8); const array = []i32{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(array[0..]) == []const i32); + expect(@typeOf(array[0..]) == []const i32); } } test "pointer child field" { - assertOrPanic((*u32).Child == u32); + expect((*u32).Child == u32); } test "struct inside function" { @@ -675,11 +675,11 @@ fn testStructInFn() void { block.kind += 1; - assertOrPanic(block.kind == 1235); + expect(block.kind == 1235); } test "fn call returning scalar optional in equality expression" { - assertOrPanic(getNull() == null); + expect(getNull() == null); } fn getNull() ?*i32 { @@ -691,5 +691,5 @@ test "thread local variable" { threadlocal var t: i32 = 1234; }; S.t += 1; - assertOrPanic(S.t == 1235); + expect(S.t == 1235); } diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig index fe3e0cc020..32feaced10 100644 --- a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig +++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig @@ -1,11 +1,11 @@ const builtin = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "namespace depends on compile var" { if (some_namespace.a_bool) { - assertOrPanic(some_namespace.a_bool); + expect(some_namespace.a_bool); } else { - assertOrPanic(!some_namespace.a_bool); + expect(!some_namespace.a_bool); } } const some_namespace = switch (builtin.os) { diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig index b9ae2d27cd..1e01a5a8a2 100644 --- a/test/stage1/behavior/new_stack_call.zig +++ b/test/stage1/behavior/new_stack_call.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; var new_stack_bytes: [1024]u8 = undefined; @@ -10,17 +10,17 @@ test "calling a function with a new stack" { const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); _ = targetFunction(arg); - assertOrPanic(arg == 1234); - assertOrPanic(a < b); + expect(arg == 1234); + expect(a < b); } fn targetFunction(x: i32) usize { - assertOrPanic(x == 1234); + expect(x == 1234); var local_variable: i32 = 42; const ptr = &local_variable; ptr.* += 1; - assertOrPanic(local_variable == 43); + expect(local_variable == 43); return @ptrToInt(ptr); } diff --git a/test/stage1/behavior/null.zig b/test/stage1/behavior/null.zig index e2f86a05ba..8c9b86b260 100644 --- a/test/stage1/behavior/null.zig +++ b/test/stage1/behavior/null.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "optional type" { const x: ?bool = true; @@ -17,13 +17,13 @@ test "optional type" { const z = next_x orelse 1234; - assertOrPanic(z == 1234); + expect(z == 1234); const final_x: ?i32 = 13; const num = final_x orelse unreachable; - assertOrPanic(num == 13); + expect(num == 13); } test "test maybe object and get a pointer to the inner value" { @@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" { b.* = false; } - assertOrPanic(maybe_bool.? == false); + expect(maybe_bool.? == false); } test "rhs maybe unwrap return" { @@ -47,9 +47,9 @@ test "maybe return" { } fn maybeReturnImpl() void { - assertOrPanic(foo(1235).?); + expect(foo(1235).?); if (foo(null) != null) unreachable; - assertOrPanic(!foo(1234).?); + expect(!foo(1234).?); } fn foo(x: ?i32) ?bool { @@ -58,7 +58,7 @@ fn foo(x: ?i32) ?bool { } test "if var maybe pointer" { - assertOrPanic(shouldBeAPlus1(Particle{ + expect(shouldBeAPlus1(Particle{ .a = 14, .b = 1, .c = 1, @@ -84,10 +84,10 @@ const Particle = struct { test "null literal outside function" { const is_null = here_is_a_null_literal.context == null; - assertOrPanic(is_null); + expect(is_null); const is_non_null = here_is_a_null_literal.context != null; - assertOrPanic(!is_non_null); + expect(!is_non_null); } const SillyStruct = struct { context: ?i32, @@ -98,8 +98,8 @@ test "test null runtime" { testTestNullRuntime(null); } fn testTestNullRuntime(x: ?i32) void { - assertOrPanic(x == null); - assertOrPanic(!(x != null)); + expect(x == null); + expect(!(x != null)); } test "optional void" { @@ -108,8 +108,8 @@ test "optional void" { } fn optionalVoidImpl() void { - assertOrPanic(bar(null) == null); - assertOrPanic(bar({}) != null); + expect(bar(null) == null); + expect(bar({}) != null); } fn bar(x: ?void) ?void { @@ -133,7 +133,7 @@ test "unwrap optional which is field of global var" { } struct_with_optional.field = 1234; if (struct_with_optional.field) |payload| { - assertOrPanic(payload == 1234); + expect(payload == 1234); } else { unreachable; } @@ -141,13 +141,13 @@ test "unwrap optional which is field of global var" { test "null with default unwrap" { const x: i32 = null orelse 1; - assertOrPanic(x == 1); + expect(x == 1); } test "optional types" { comptime { const opt_type_struct = StructWithOptionalType{ .t = u8 }; - assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8); + expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); } } @@ -158,5 +158,5 @@ const StructWithOptionalType = struct { test "optional pointer to 0 bit type null value at runtime" { const EmptyStruct = struct {}; var x: ?*EmptyStruct = null; - assertOrPanic(x == null); + expect(x == null); } diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 14692cb1ea..a65bed020c 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -1,11 +1,11 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; pub const EmptyStruct = struct {}; test "optional pointer to size zero struct" { var e = EmptyStruct{}; var o: ?*EmptyStruct = &e; - assertOrPanic(o != null); + expect(o != null); } test "equality compare nullable pointers" { @@ -18,15 +18,15 @@ fn testNullPtrsEql() void { var x: ?*i32 = null; var y: ?*i32 = null; - assertOrPanic(x == y); + expect(x == y); y = &number; - assertOrPanic(x != y); - assertOrPanic(x != &number); - assertOrPanic(&number != x); + expect(x != y); + expect(x != &number); + expect(&number != x); x = &number; - assertOrPanic(x == y); - assertOrPanic(x == &number); - assertOrPanic(&number == x); + expect(x == y); + expect(x == &number); + expect(&number == x); } test "address of unwrap optional" { @@ -43,7 +43,7 @@ test "address of unwrap optional" { }; S.global = S.Foo{ .a = 1234 }; const foo = S.getFoo() catch unreachable; - assertOrPanic(foo.a == 1234); + expect(foo.a == 1234); } test "passing an optional integer as a parameter" { @@ -57,15 +57,15 @@ test "passing an optional integer as a parameter" { return x.? == 1234; } }; - assertOrPanic(S.entry()); - comptime assertOrPanic(S.entry()); + expect(S.entry()); + comptime expect(S.entry()); } test "unwrap function call with optional pointer return value" { const S = struct { fn entry() void { - assertOrPanic(foo().?.* == 1234); - assertOrPanic(bar() == null); + expect(foo().?.* == 1234); + expect(bar() == null); } const global: i32 = 1234; fn foo() ?*const i32 { diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 1142d89ab5..47b19700ee 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "dereference pointer" { comptime testDerefPtr(); @@ -10,33 +10,33 @@ fn testDerefPtr() void { var x: i32 = 1234; var y = &x; y.* += 1; - assertOrPanic(x == 1235); + expect(x == 1235); } test "pointer arithmetic" { var ptr = c"abcd"; - assertOrPanic(ptr[0] == 'a'); + expect(ptr[0] == 'a'); ptr += 1; - assertOrPanic(ptr[0] == 'b'); + expect(ptr[0] == 'b'); ptr += 1; - assertOrPanic(ptr[0] == 'c'); + expect(ptr[0] == 'c'); ptr += 1; - assertOrPanic(ptr[0] == 'd'); + expect(ptr[0] == 'd'); ptr += 1; - assertOrPanic(ptr[0] == 0); + expect(ptr[0] == 0); ptr -= 1; - assertOrPanic(ptr[0] == 'd'); + expect(ptr[0] == 'd'); ptr -= 1; - assertOrPanic(ptr[0] == 'c'); + expect(ptr[0] == 'c'); ptr -= 1; - assertOrPanic(ptr[0] == 'b'); + expect(ptr[0] == 'b'); ptr -= 1; - assertOrPanic(ptr[0] == 'a'); + expect(ptr[0] == 'a'); } test "double pointer parsing" { - comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32); + comptime expect(PtrOf(PtrOf(i32)) == **i32); } fn PtrOf(comptime T: type) type { diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig index f7f8bb523b..2b63284720 100644 --- a/test/stage1/behavior/popcount.zig +++ b/test/stage1/behavior/popcount.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@popCount" { comptime testPopCount(); @@ -8,18 +8,18 @@ test "@popCount" { fn testPopCount() void { { var x: u32 = 0xaa; - assertOrPanic(@popCount(x) == 4); + expect(@popCount(x) == 4); } { var x: u32 = 0xaaaaaaaa; - assertOrPanic(@popCount(x) == 16); + expect(@popCount(x) == 16); } { var x: i16 = -1; - assertOrPanic(@popCount(x) == 16); + expect(@popCount(x) == 16); } comptime { - assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); + expect(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); } } diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 54c3dda849..3787382aea 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -1,6 +1,6 @@ const builtin = @import("builtin"); const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "reinterpret bytes as integer with nonzero offset" { testReinterpretBytesAsInteger(); @@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void { builtin.Endian.Little => 0xab785634, builtin.Endian.Big => 0x345678ab, }; - assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); + expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); } test "reinterpret bytes of an array into an extern struct" { @@ -32,12 +32,12 @@ fn testReinterpretBytesAsExternStruct() void { var ptr = @ptrCast(*const S, &bytes); var val = ptr.c; - assertOrPanic(val == 5); + expect(val == 5); } test "reinterpret struct field at comptime" { const numLittle = comptime Bytes.init(0x12345678); - assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); + expect(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); } const Bytes = struct { diff --git a/test/stage1/behavior/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig index 181113f6bf..15e4114c2d 100644 --- a/test/stage1/behavior/pub_enum/index.zig +++ b/test/stage1/behavior/pub_enum/index.zig @@ -1,13 +1,13 @@ const other = @import("other.zig"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "pub enum" { pubEnumTest(other.APubEnum.Two); } fn pubEnumTest(foo: other.APubEnum) void { - assertOrPanic(foo == other.APubEnum.Two); + expect(foo == other.APubEnum.Two); } test "cast with imported symbol" { - assertOrPanic(other.size_t(42) == 42); + expect(other.size_t(42) == 42); } diff --git a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig index acbe6b2459..2c1cf06268 100644 --- a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig +++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -1,14 +1,14 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; var ok: bool = false; test "reference a variable in an if after an if in the 2nd switch prong" { foo(true, Num.Two, false, "aoeu"); - assertOrPanic(!ok); + expect(!ok); foo(false, Num.One, false, "aoeu"); - assertOrPanic(!ok); + expect(!ok); foo(true, Num.One, false, "aoeu"); - assertOrPanic(ok); + expect(ok); } const Num = enum { @@ -32,6 +32,6 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { } fn a(x: []const u8) void { - assertOrPanic(mem.eql(u8, x, "aoeu")); + expect(mem.eql(u8, x, "aoeu")); ok = true; } diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig index f4c142e0f7..55efc85b97 100644 --- a/test/stage1/behavior/reflection.zig +++ b/test/stage1/behavior/reflection.zig @@ -1,25 +1,25 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const reflection = @This(); test "reflection: array, pointer, optional, error union type child" { comptime { - assertOrPanic(([10]u8).Child == u8); - assertOrPanic((*u8).Child == u8); - assertOrPanic((anyerror!u8).Payload == u8); - assertOrPanic((?u8).Child == u8); + expect(([10]u8).Child == u8); + expect((*u8).Child == u8); + expect((anyerror!u8).Payload == u8); + expect((?u8).Child == u8); } } test "reflection: function return type, var args, and param types" { comptime { - assertOrPanic(@typeOf(dummy).ReturnType == i32); - assertOrPanic(!@typeOf(dummy).is_var_args); - assertOrPanic(@typeOf(dummy_varargs).is_var_args); - assertOrPanic(@typeOf(dummy).arg_count == 3); - assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool); - assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32); - assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32); + expect(@typeOf(dummy).ReturnType == i32); + expect(!@typeOf(dummy).is_var_args); + expect(@typeOf(dummy_varargs).is_var_args); + expect(@typeOf(dummy).arg_count == 3); + expect(@ArgType(@typeOf(dummy), 0) == bool); + expect(@ArgType(@typeOf(dummy), 1) == i32); + expect(@ArgType(@typeOf(dummy), 2) == f32); } } @@ -30,31 +30,31 @@ fn dummy_varargs(args: ...) void {} test "reflection: struct member types and names" { comptime { - assertOrPanic(@memberCount(Foo) == 3); + expect(@memberCount(Foo) == 3); - assertOrPanic(@memberType(Foo, 0) == i32); - assertOrPanic(@memberType(Foo, 1) == bool); - assertOrPanic(@memberType(Foo, 2) == void); + expect(@memberType(Foo, 0) == i32); + expect(@memberType(Foo, 1) == bool); + expect(@memberType(Foo, 2) == void); - assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one")); - assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two")); - assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three")); + expect(mem.eql(u8, @memberName(Foo, 0), "one")); + expect(mem.eql(u8, @memberName(Foo, 1), "two")); + expect(mem.eql(u8, @memberName(Foo, 2), "three")); } } test "reflection: enum member types and names" { comptime { - assertOrPanic(@memberCount(Bar) == 4); + expect(@memberCount(Bar) == 4); - assertOrPanic(@memberType(Bar, 0) == void); - assertOrPanic(@memberType(Bar, 1) == i32); - assertOrPanic(@memberType(Bar, 2) == bool); - assertOrPanic(@memberType(Bar, 3) == f64); + expect(@memberType(Bar, 0) == void); + expect(@memberType(Bar, 1) == i32); + expect(@memberType(Bar, 2) == bool); + expect(@memberType(Bar, 3) == f64); - assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four")); + expect(mem.eql(u8, @memberName(Bar, 0), "One")); + expect(mem.eql(u8, @memberName(Bar, 1), "Two")); + expect(mem.eql(u8, @memberName(Bar, 2), "Three")); + expect(mem.eql(u8, @memberName(Bar, 3), "Four")); } } @@ -65,18 +65,18 @@ test "reflection: @field" { .three = void{}, }; - assertOrPanic(f.one == f.one); - assertOrPanic(@field(f, "o" ++ "ne") == f.one); - assertOrPanic(@field(f, "t" ++ "wo") == f.two); - assertOrPanic(@field(f, "th" ++ "ree") == f.three); - assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant); - assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One); - assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two); - assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three); - assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four); - assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); + expect(f.one == f.one); + expect(@field(f, "o" ++ "ne") == f.one); + expect(@field(f, "t" ++ "wo") == f.two); + expect(@field(f, "th" ++ "ree") == f.three); + expect(@field(Foo, "const" ++ "ant") == Foo.constant); + expect(@field(Bar, "O" ++ "ne") == Bar.One); + expect(@field(Bar, "T" ++ "wo") == Bar.Two); + expect(@field(Bar, "Th" ++ "ree") == Bar.Three); + expect(@field(Bar, "F" ++ "our") == Bar.Four); + expect(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); @field(f, "o" ++ "ne") = 4; - assertOrPanic(f.one == 4); + expect(f.one == 4); } const Foo = struct { diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig index ddaea4c242..58a6c81759 100644 --- a/test/stage1/behavior/sizeof_and_typeof.zig +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -1,9 +1,9 @@ const builtin = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@sizeOf and @typeOf" { const y: @typeOf(x) = 120; - assertOrPanic(@sizeOf(@typeOf(y)) == 2); + expect(@sizeOf(@typeOf(y)) == 2); } const x: u16 = 13; const z: @typeOf(x) = 19; @@ -30,40 +30,40 @@ const P = packed struct { test "@byteOffsetOf" { // Packed structs have fixed memory layout - assertOrPanic(@byteOffsetOf(P, "a") == 0); - assertOrPanic(@byteOffsetOf(P, "b") == 1); - assertOrPanic(@byteOffsetOf(P, "c") == 5); - assertOrPanic(@byteOffsetOf(P, "d") == 6); - assertOrPanic(@byteOffsetOf(P, "e") == 6); - assertOrPanic(@byteOffsetOf(P, "f") == 7); - assertOrPanic(@byteOffsetOf(P, "g") == 9); + expect(@byteOffsetOf(P, "a") == 0); + expect(@byteOffsetOf(P, "b") == 1); + expect(@byteOffsetOf(P, "c") == 5); + expect(@byteOffsetOf(P, "d") == 6); + expect(@byteOffsetOf(P, "e") == 6); + expect(@byteOffsetOf(P, "f") == 7); + expect(@byteOffsetOf(P, "g") == 9); // Normal struct fields can be moved/padded var a: A = undefined; - assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); - assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); - assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); - assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); - assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); - assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); - assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); + expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); + expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); + expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); + expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); + expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); + expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); + expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); } test "@bitOffsetOf" { // Packed structs have fixed memory layout - assertOrPanic(@bitOffsetOf(P, "a") == 0); - assertOrPanic(@bitOffsetOf(P, "b") == 8); - assertOrPanic(@bitOffsetOf(P, "c") == 40); - assertOrPanic(@bitOffsetOf(P, "d") == 48); - assertOrPanic(@bitOffsetOf(P, "e") == 51); - assertOrPanic(@bitOffsetOf(P, "f") == 56); - assertOrPanic(@bitOffsetOf(P, "g") == 72); + expect(@bitOffsetOf(P, "a") == 0); + expect(@bitOffsetOf(P, "b") == 8); + expect(@bitOffsetOf(P, "c") == 40); + expect(@bitOffsetOf(P, "d") == 48); + expect(@bitOffsetOf(P, "e") == 51); + expect(@bitOffsetOf(P, "f") == 56); + expect(@bitOffsetOf(P, "g") == 72); - assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); - assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); - assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); - assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); - assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); - assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); - assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); + expect(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); + expect(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); + expect(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); + expect(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); + expect(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); + expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); + expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); } diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index cc29e43485..13fa84d0fa 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -1,20 +1,20 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { - assertOrPanic(@ptrToInt(x.ptr) == 0x1000); - assertOrPanic(x.len == 0x500); + expect(@ptrToInt(x.ptr) == 0x1000); + expect(x.len == 0x500); - assertOrPanic(@ptrToInt(y.ptr) == 0x1100); - assertOrPanic(y.len == 0x400); + expect(@ptrToInt(y.ptr) == 0x1100); + expect(y.len == 0x400); } test "slice child property" { var array: [5]i32 = undefined; var slice = array[0..]; - assertOrPanic(@typeOf(slice).Child == i32); + expect(@typeOf(slice).Child == i32); } test "runtime safety lets us slice from len..len" { @@ -23,7 +23,7 @@ test "runtime safety lets us slice from len..len" { 2, 3, }; - assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); + expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); } fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { @@ -36,5 +36,5 @@ test "implicitly cast array of size 0 to slice" { } fn assertLenIsZero(msg: []const u8) void { - assertOrPanic(msg.len == 0); + expect(msg.len == 0); } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 92ae2baa15..a045f482a2 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -12,7 +12,7 @@ const empty_global_instance = StructWithNoFields{}; test "call struct static method" { const result = StructWithNoFields.add(3, 4); - assertOrPanic(result == 7); + expect(result == 7); } test "return empty struct instance" { @@ -25,7 +25,7 @@ fn returnEmptyStructInstance() StructWithNoFields { const should_be_11 = StructWithNoFields.add(5, 6); test "invoke static method in global scope" { - assertOrPanic(should_be_11 == 11); + expect(should_be_11 == 11); } test "void struct fields" { @@ -34,8 +34,8 @@ test "void struct fields" { .b = 1, .c = void{}, }; - assertOrPanic(foo.b == 1); - assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4); + expect(foo.b == 1); + expect(@sizeOf(VoidStructFieldsFoo) == 4); } const VoidStructFieldsFoo = struct { a: void, @@ -50,7 +50,7 @@ test "structs" { foo.b = foo.a == 1; testFoo(foo); testMutation(&foo); - assertOrPanic(foo.c == 100); + expect(foo.c == 100); } const StructFoo = struct { a: i32, @@ -58,7 +58,7 @@ const StructFoo = struct { c: f32, }; fn testFoo(foo: StructFoo) void { - assertOrPanic(foo.b); + expect(foo.b); } fn testMutation(foo: *StructFoo) void { foo.c = 100; @@ -83,7 +83,7 @@ test "struct point to self" { root.next = &node; - assertOrPanic(node.next.next.next.val.x == 1); + expect(node.next.next.next.val.x == 1); } test "struct byval assign" { @@ -92,18 +92,18 @@ test "struct byval assign" { foo1.a = 1234; foo2.a = 0; - assertOrPanic(foo2.a == 0); + expect(foo2.a == 0); foo2 = foo1; - assertOrPanic(foo2.a == 1234); + expect(foo2.a == 1234); } fn structInitializer() void { const val = Val{ .x = 42 }; - assertOrPanic(val.x == 42); + expect(val.x == 42); } test "fn call of struct field" { - assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13); + expect(callStructField(Foo{ .ptr = aFunc }) == 13); } const Foo = struct { @@ -122,7 +122,7 @@ test "store member function in variable" { const instance = MemberFnTestFoo{ .x = 1234 }; const memberFn = MemberFnTestFoo.member; const result = memberFn(instance); - assertOrPanic(result == 1234); + expect(result == 1234); } const MemberFnTestFoo = struct { x: i32, @@ -134,12 +134,12 @@ const MemberFnTestFoo = struct { test "call member function directly" { const instance = MemberFnTestFoo{ .x = 1234 }; const result = MemberFnTestFoo.member(instance); - assertOrPanic(result == 1234); + expect(result == 1234); } test "member functions" { const r = MemberFnRand{ .seed = 1234 }; - assertOrPanic(r.getSeed() == 1234); + expect(r.getSeed() == 1234); } const MemberFnRand = struct { seed: u32, @@ -150,7 +150,7 @@ const MemberFnRand = struct { test "return struct byval from function" { const bar = makeBar(1234, 5678); - assertOrPanic(bar.y == 5678); + expect(bar.y == 5678); } const Bar = struct { x: i32, @@ -165,7 +165,7 @@ fn makeBar(x: i32, y: i32) Bar { test "empty struct method call" { const es = EmptyStruct{}; - assertOrPanic(es.method() == 1234); + expect(es.method() == 1234); } const EmptyStruct = struct { fn method(es: *const EmptyStruct) i32 { @@ -182,7 +182,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 { } test "pass slice of empty struct to fn" { - assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); + expect(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); } fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { return slice.len; @@ -200,7 +200,7 @@ test "packed struct" { }; foo.y += 1; const four = foo.x + foo.y; - assertOrPanic(four == 4); + expect(four == 4); } const BitField1 = packed struct { @@ -217,17 +217,17 @@ const bit_field_1 = BitField1{ test "bit field access" { var data = bit_field_1; - assertOrPanic(getA(&data) == 1); - assertOrPanic(getB(&data) == 2); - assertOrPanic(getC(&data) == 3); - comptime assertOrPanic(@sizeOf(BitField1) == 1); + expect(getA(&data) == 1); + expect(getB(&data) == 2); + expect(getC(&data) == 3); + comptime expect(@sizeOf(BitField1) == 1); data.b += 1; - assertOrPanic(data.b == 3); + expect(data.b == 3); data.a += 1; - assertOrPanic(data.a == 2); - assertOrPanic(data.b == 3); + expect(data.a == 2); + expect(data.b == 3); } fn getA(data: *const BitField1) u3 { @@ -254,8 +254,8 @@ const Foo96Bits = packed struct { test "packed struct 24bits" { comptime { - assertOrPanic(@sizeOf(Foo24Bits) == 3); - assertOrPanic(@sizeOf(Foo96Bits) == 12); + expect(@sizeOf(Foo24Bits) == 3); + expect(@sizeOf(Foo96Bits) == 12); } var value = Foo96Bits{ @@ -265,28 +265,28 @@ test "packed struct 24bits" { .d = 0, }; value.a += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 0); - assertOrPanic(value.c == 0); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 0); + expect(value.c == 0); + expect(value.d == 0); value.b += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 0); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 0); + expect(value.d == 0); value.c += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 1); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 1); + expect(value.d == 0); value.d += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 1); - assertOrPanic(value.d == 1); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 1); + expect(value.d == 1); } const FooArray24Bits = packed struct { @@ -297,43 +297,43 @@ const FooArray24Bits = packed struct { test "packed array 24bits" { comptime { - assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3); - assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); + expect(@sizeOf([9]Foo24Bits) == 9 * 3); + expect(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); } var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); bytes[bytes.len - 1] = 0xaa; const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; - assertOrPanic(ptr.a == 0); - assertOrPanic(ptr.b[0].field == 0); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == 0); + expect(ptr.b[0].field == 0); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.a = maxInt(u16); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == 0); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == 0); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.b[0].field = maxInt(u24); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.b[1].field = maxInt(u24); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == maxInt(u24)); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == maxInt(u24)); + expect(ptr.c == 0); ptr.c = maxInt(u16); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == maxInt(u24)); - assertOrPanic(ptr.c == maxInt(u16)); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == maxInt(u24)); + expect(ptr.c == maxInt(u16)); - assertOrPanic(bytes[bytes.len - 1] == 0xaa); + expect(bytes[bytes.len - 1] == 0xaa); } const FooStructAligned = packed struct { @@ -347,17 +347,17 @@ const FooArrayOfAligned = packed struct { test "aligned array of packed struct" { comptime { - assertOrPanic(@sizeOf(FooStructAligned) == 2); - assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2); + expect(@sizeOf(FooStructAligned) == 2); + expect(@sizeOf(FooArrayOfAligned) == 2 * 2); } var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; - assertOrPanic(ptr.a[0].a == 0xbb); - assertOrPanic(ptr.a[0].b == 0xbb); - assertOrPanic(ptr.a[1].a == 0xbb); - assertOrPanic(ptr.a[1].b == 0xbb); + expect(ptr.a[0].a == 0xbb); + expect(ptr.a[0].b == 0xbb); + expect(ptr.a[1].a == 0xbb); + expect(ptr.a[1].b == 0xbb); } test "runtime struct initialization of bitfield" { @@ -370,10 +370,10 @@ test "runtime struct initialization of bitfield" { .y = @intCast(u4, x2), }; - assertOrPanic(s1.x == x1); - assertOrPanic(s1.y == x1); - assertOrPanic(s2.x == @intCast(u4, x2)); - assertOrPanic(s2.y == @intCast(u4, x2)); + expect(s1.x == x1); + expect(s1.y == x1); + expect(s2.x == @intCast(u4, x2)); + expect(s2.y == @intCast(u4, x2)); } var x1 = u4(1); @@ -400,18 +400,18 @@ test "native bit field understands endianness" { @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; - assertOrPanic(bitfields.f1 == 0x1111); - assertOrPanic(bitfields.f2 == 0x2222); - assertOrPanic(bitfields.f3 == 0x33); - assertOrPanic(bitfields.f4 == 0x44); - assertOrPanic(bitfields.f5 == 0x5); - assertOrPanic(bitfields.f6 == 0x6); - assertOrPanic(bitfields.f7 == 0x77); + expect(bitfields.f1 == 0x1111); + expect(bitfields.f2 == 0x2222); + expect(bitfields.f3 == 0x33); + expect(bitfields.f4 == 0x44); + expect(bitfields.f5 == 0x5); + expect(bitfields.f6 == 0x6); + expect(bitfields.f7 == 0x77); } test "align 1 field before self referential align 8 field as slice return type" { const result = alloc(Expr); - assertOrPanic(result.len == 0); + expect(result.len == 0); } const Expr = union(enum) { @@ -434,10 +434,10 @@ test "call method with mutable reference to struct with no fields" { }; var s = S{}; - assertOrPanic(S.doC(&s)); - assertOrPanic(s.doC()); - assertOrPanic(S.do(&s)); - assertOrPanic(s.do()); + expect(S.doC(&s)); + expect(s.doC()); + expect(S.do(&s)); + expect(s.do()); } test "implicit cast packed struct field to const ptr" { @@ -453,7 +453,7 @@ test "implicit cast packed struct field to const ptr" { var lup: LevelUpMove = undefined; lup.level = 12; const res = LevelUpMove.toInt(lup.level); - assertOrPanic(res == 12); + expect(res == 12); } test "pointer to packed struct member in a stack variable" { @@ -464,7 +464,7 @@ test "pointer to packed struct member in a stack variable" { var s = S{ .a = 2, .b = 0 }; var b_ptr = &s.b; - assertOrPanic(s.b == 0); + expect(s.b == 0); b_ptr.* = 2; - assertOrPanic(s.b == 2); + expect(s.b == 2); } diff --git a/test/stage1/behavior/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig index 4cc479f31c..991d742cec 100644 --- a/test/stage1/behavior/struct_contains_null_ptr_itself.zig +++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "struct contains null pointer which contains original struct" { var x: ?*NodeLineComment = null; - assertOrPanic(x == null); + expect(x == null); } pub const Node = struct { diff --git a/test/stage1/behavior/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig index 15780a7c44..52c6579654 100644 --- a/test/stage1/behavior/struct_contains_slice_of_itself.zig +++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Node = struct { payload: i32, @@ -39,12 +39,12 @@ test "struct contains slice of itself" { .payload = 1234, .children = nodes[0..], }; - assertOrPanic(root.payload == 1234); - assertOrPanic(root.children[0].payload == 1); - assertOrPanic(root.children[1].payload == 2); - assertOrPanic(root.children[2].payload == 3); - assertOrPanic(root.children[2].children[0].payload == 31); - assertOrPanic(root.children[2].children[1].payload == 32); + expect(root.payload == 1234); + expect(root.children[0].payload == 1); + expect(root.children[1].payload == 2); + expect(root.children[2].payload == 3); + expect(root.children[2].children[0].payload == 31); + expect(root.children[2].children[1].payload == 32); } test "struct contains aligned slice of itself" { @@ -76,10 +76,10 @@ test "struct contains aligned slice of itself" { .payload = 1234, .children = nodes[0..], }; - assertOrPanic(root.payload == 1234); - assertOrPanic(root.children[0].payload == 1); - assertOrPanic(root.children[1].payload == 2); - assertOrPanic(root.children[2].payload == 3); - assertOrPanic(root.children[2].children[0].payload == 31); - assertOrPanic(root.children[2].children[1].payload == 32); + expect(root.payload == 1234); + expect(root.children[0].payload == 1); + expect(root.children[1].payload == 2); + expect(root.children[2].payload == 3); + expect(root.children[2].children[0].payload == 31); + expect(root.children[2].children[1].payload == 32); } diff --git a/test/stage1/behavior/switch.zig b/test/stage1/behavior/switch.zig index 4ac971397e..1059bf28f8 100644 --- a/test/stage1/behavior/switch.zig +++ b/test/stage1/behavior/switch.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "switch with numbers" { testSwitchWithNumbers(13); @@ -10,14 +10,14 @@ fn testSwitchWithNumbers(x: u32) void { 13 => true, else => false, }; - assertOrPanic(result); + expect(result); } test "switch with all ranges" { - assertOrPanic(testSwitchWithAllRanges(50, 3) == 1); - assertOrPanic(testSwitchWithAllRanges(101, 0) == 2); - assertOrPanic(testSwitchWithAllRanges(300, 5) == 3); - assertOrPanic(testSwitchWithAllRanges(301, 6) == 6); + expect(testSwitchWithAllRanges(50, 3) == 1); + expect(testSwitchWithAllRanges(101, 0) == 2); + expect(testSwitchWithAllRanges(300, 5) == 3); + expect(testSwitchWithAllRanges(301, 6) == 6); } fn testSwitchWithAllRanges(x: u32, y: u32) u32 { @@ -40,7 +40,7 @@ test "implicit comptime switch" { }; comptime { - assertOrPanic(result + 1 == 14); + expect(result + 1 == 14); } } @@ -71,7 +71,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) void { SwitchStatmentFoo.C => 3, SwitchStatmentFoo.D => 4, }; - assertOrPanic(val == 3); + expect(val == 3); } const SwitchStatmentFoo = enum { A, @@ -93,10 +93,10 @@ const SwitchProngWithVarEnum = union(enum) { fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { switch (a) { SwitchProngWithVarEnum.One => |x| { - assertOrPanic(x == 13); + expect(x == 13); }, SwitchProngWithVarEnum.Two => |x| { - assertOrPanic(x == 13.0); + expect(x == 13.0); }, SwitchProngWithVarEnum.Meh => |x| { const v: void = x; @@ -116,7 +116,7 @@ fn testSwitchEnumPtrCapture() void { else => unreachable, } switch (value) { - SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235), + SwitchProngWithVarEnum.One => |x| expect(x == 1235), else => unreachable, } } @@ -127,7 +127,7 @@ test "switch with multiple expressions" { 4, 5, 6 => 2, else => i32(3), }; - assertOrPanic(x == 2); + expect(x == 2); } fn returnsFive() i32 { return 5; @@ -149,12 +149,12 @@ fn returnsFalse() bool { } } test "switch on const enum with var" { - assertOrPanic(!returnsFalse()); + expect(!returnsFalse()); } test "switch on type" { - assertOrPanic(trueIfBoolFalseOtherwise(bool)); - assertOrPanic(!trueIfBoolFalseOtherwise(i32)); + expect(trueIfBoolFalseOtherwise(bool)); + expect(!trueIfBoolFalseOtherwise(i32)); } fn trueIfBoolFalseOtherwise(comptime T: type) bool { @@ -170,16 +170,16 @@ test "switch handles all cases of number" { } fn testSwitchHandleAllCases() void { - assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3); - assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2); - assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1); - assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0); + expect(testSwitchHandleAllCasesExhaustive(0) == 3); + expect(testSwitchHandleAllCasesExhaustive(1) == 2); + expect(testSwitchHandleAllCasesExhaustive(2) == 1); + expect(testSwitchHandleAllCasesExhaustive(3) == 0); - assertOrPanic(testSwitchHandleAllCasesRange(100) == 0); - assertOrPanic(testSwitchHandleAllCasesRange(200) == 1); - assertOrPanic(testSwitchHandleAllCasesRange(201) == 2); - assertOrPanic(testSwitchHandleAllCasesRange(202) == 4); - assertOrPanic(testSwitchHandleAllCasesRange(230) == 3); + expect(testSwitchHandleAllCasesRange(100) == 0); + expect(testSwitchHandleAllCasesRange(200) == 1); + expect(testSwitchHandleAllCasesRange(201) == 2); + expect(testSwitchHandleAllCasesRange(202) == 4); + expect(testSwitchHandleAllCasesRange(230) == 3); } fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { @@ -207,8 +207,8 @@ test "switch all prongs unreachable" { } fn testAllProngsUnreachable() void { - assertOrPanic(switchWithUnreachable(1) == 2); - assertOrPanic(switchWithUnreachable(2) == 10); + expect(switchWithUnreachable(1) == 2); + expect(switchWithUnreachable(2) == 10); } fn switchWithUnreachable(x: i32) i32 { @@ -230,7 +230,7 @@ test "capture value of switch with all unreachable prongs" { const x = return_a_number() catch |err| switch (err) { else => unreachable, }; - assertOrPanic(x == 1); + expect(x == 1); } test "switching on booleans" { @@ -239,14 +239,14 @@ test "switching on booleans" { } fn testSwitchOnBools() void { - assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false); - assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true); + expect(testSwitchOnBoolsTrueAndFalse(true) == false); + expect(testSwitchOnBoolsTrueAndFalse(false) == true); - assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false); - assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true); + expect(testSwitchOnBoolsTrueWithElse(true) == false); + expect(testSwitchOnBoolsTrueWithElse(false) == true); - assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false); - assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true); + expect(testSwitchOnBoolsFalseWithElse(true) == false); + expect(testSwitchOnBoolsFalseWithElse(false) == true); } fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { diff --git a/test/stage1/behavior/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig index 6ac1919f0d..3593eabb5a 100644 --- a/test/stage1/behavior/switch_prong_err_enum.zig +++ b/test/stage1/behavior/switch_prong_err_enum.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; var read_count: u64 = 0; @@ -22,9 +22,9 @@ fn doThing(form_id: u64) anyerror!FormValue { test "switch prong returns error enum" { switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { - assertOrPanic(payload == 1); + expect(payload == 1); }, else => unreachable, } - assertOrPanic(read_count == 1); + expect(read_count == 1); } diff --git a/test/stage1/behavior/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig index 4ca031e2e1..da965915ca 100644 --- a/test/stage1/behavior/switch_prong_implicit_cast.zig +++ b/test/stage1/behavior/switch_prong_implicit_cast.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const FormValue = union(enum) { One: void, @@ -18,5 +18,5 @@ test "switch prong implicit cast" { FormValue.One => false, FormValue.Two => |x| x, }; - assertOrPanic(result); + expect(result); } diff --git a/test/stage1/behavior/this.zig b/test/stage1/behavior/this.zig index 0e3a7a03ae..a0bee3a3ee 100644 --- a/test/stage1/behavior/this.zig +++ b/test/stage1/behavior/this.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const module = @This(); @@ -20,7 +20,7 @@ fn add(x: i32, y: i32) i32 { } test "this refer to module call private fn" { - assertOrPanic(module.add(1, 2) == 3); + expect(module.add(1, 2) == 3); } test "this refer to container" { @@ -29,7 +29,7 @@ test "this refer to container" { .y = 34, }; pt.addOne(); - assertOrPanic(pt.x == 13); - assertOrPanic(pt.y == 35); + expect(pt.x == 13); + expect(pt.y == 35); } diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig index b7904bc7fb..c195b64cbf 100644 --- a/test/stage1/behavior/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -1,8 +1,8 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "truncate u0 to larger integer allowed and has comptime known result" { var x: u0 = 0; const y = @truncate(u8, x); - comptime assertOrPanic(y == 0); + comptime expect(y == 0); } diff --git a/test/stage1/behavior/try.zig b/test/stage1/behavior/try.zig index ed48875eb4..9c700f6260 100644 --- a/test/stage1/behavior/try.zig +++ b/test/stage1/behavior/try.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "try on error union" { tryOnErrorUnionImpl(); @@ -11,7 +11,7 @@ fn tryOnErrorUnionImpl() void { error.CrappedOut => i32(2), else => unreachable, }; - assertOrPanic(x == 11); + expect(x == 11); } fn returnsTen() anyerror!i32 { @@ -20,10 +20,10 @@ fn returnsTen() anyerror!i32 { test "try without vars" { const result1 = if (failIfTrue(true)) 1 else |_| i32(2); - assertOrPanic(result1 == 2); + expect(result1 == 2); const result2 = if (failIfTrue(false)) 1 else |_| i32(2); - assertOrPanic(result2 == 1); + expect(result2 == 1); } fn failIfTrue(ok: bool) anyerror!void { @@ -38,6 +38,6 @@ test "try then not executed with assignment" { if (failIfTrue(true)) { unreachable; } else |err| { - assertOrPanic(err == error.ItBroke); + expect(err == error.ItBroke); } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index f3bb17b282..ce0ad795b4 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const TypeInfo = @import("builtin").TypeInfo; const TypeId = @import("builtin").TypeId; @@ -9,10 +9,10 @@ test "type info: tag type, void info" { } fn testBasic() void { - assertOrPanic(@TagType(TypeInfo) == TypeId); + expect(@TagType(TypeInfo) == TypeId); const void_info = @typeInfo(void); - assertOrPanic(TypeId(void_info) == TypeId.Void); - assertOrPanic(void_info.Void == {}); + expect(TypeId(void_info) == TypeId.Void); + expect(void_info.Void == {}); } test "type info: integer, floating point type info" { @@ -22,13 +22,13 @@ test "type info: integer, floating point type info" { fn testIntFloat() void { const u8_info = @typeInfo(u8); - assertOrPanic(TypeId(u8_info) == TypeId.Int); - assertOrPanic(!u8_info.Int.is_signed); - assertOrPanic(u8_info.Int.bits == 8); + expect(TypeId(u8_info) == TypeId.Int); + expect(!u8_info.Int.is_signed); + expect(u8_info.Int.bits == 8); const f64_info = @typeInfo(f64); - assertOrPanic(TypeId(f64_info) == TypeId.Float); - assertOrPanic(f64_info.Float.bits == 64); + expect(TypeId(f64_info) == TypeId.Float); + expect(f64_info.Float.bits == 64); } test "type info: pointer type info" { @@ -38,12 +38,12 @@ test "type info: pointer type info" { fn testPointer() void { const u32_ptr_info = @typeInfo(*u32); - assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); - assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); - assertOrPanic(u32_ptr_info.Pointer.is_const == false); - assertOrPanic(u32_ptr_info.Pointer.is_volatile == false); - assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32)); - assertOrPanic(u32_ptr_info.Pointer.child == u32); + expect(TypeId(u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); + expect(u32_ptr_info.Pointer.is_const == false); + expect(u32_ptr_info.Pointer.is_volatile == false); + expect(u32_ptr_info.Pointer.alignment == @alignOf(u32)); + expect(u32_ptr_info.Pointer.child == u32); } test "type info: unknown length pointer type info" { @@ -53,12 +53,12 @@ test "type info: unknown length pointer type info" { fn testUnknownLenPtr() void { const u32_ptr_info = @typeInfo([*]const volatile f64); - assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); - assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); - assertOrPanic(u32_ptr_info.Pointer.is_const == true); - assertOrPanic(u32_ptr_info.Pointer.is_volatile == true); - assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64)); - assertOrPanic(u32_ptr_info.Pointer.child == f64); + expect(TypeId(u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); + expect(u32_ptr_info.Pointer.is_const == true); + expect(u32_ptr_info.Pointer.is_volatile == true); + expect(u32_ptr_info.Pointer.alignment == @alignOf(f64)); + expect(u32_ptr_info.Pointer.child == f64); } test "type info: slice type info" { @@ -68,12 +68,12 @@ test "type info: slice type info" { fn testSlice() void { const u32_slice_info = @typeInfo([]u32); - assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer); - assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); - assertOrPanic(u32_slice_info.Pointer.is_const == false); - assertOrPanic(u32_slice_info.Pointer.is_volatile == false); - assertOrPanic(u32_slice_info.Pointer.alignment == 4); - assertOrPanic(u32_slice_info.Pointer.child == u32); + expect(TypeId(u32_slice_info) == TypeId.Pointer); + expect(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); + expect(u32_slice_info.Pointer.is_const == false); + expect(u32_slice_info.Pointer.is_volatile == false); + expect(u32_slice_info.Pointer.alignment == 4); + expect(u32_slice_info.Pointer.child == u32); } test "type info: array type info" { @@ -83,9 +83,9 @@ test "type info: array type info" { fn testArray() void { const arr_info = @typeInfo([42]bool); - assertOrPanic(TypeId(arr_info) == TypeId.Array); - assertOrPanic(arr_info.Array.len == 42); - assertOrPanic(arr_info.Array.child == bool); + expect(TypeId(arr_info) == TypeId.Array); + expect(arr_info.Array.len == 42); + expect(arr_info.Array.child == bool); } test "type info: optional type info" { @@ -95,8 +95,8 @@ test "type info: optional type info" { fn testOptional() void { const null_info = @typeInfo(?void); - assertOrPanic(TypeId(null_info) == TypeId.Optional); - assertOrPanic(null_info.Optional.child == void); + expect(TypeId(null_info) == TypeId.Optional); + expect(null_info.Optional.child == void); } test "type info: promise info" { @@ -106,12 +106,12 @@ test "type info: promise info" { fn testPromise() void { const null_promise_info = @typeInfo(promise); - assertOrPanic(TypeId(null_promise_info) == TypeId.Promise); - assertOrPanic(null_promise_info.Promise.child == null); + expect(TypeId(null_promise_info) == TypeId.Promise); + expect(null_promise_info.Promise.child == null); const promise_info = @typeInfo(promise->usize); - assertOrPanic(TypeId(promise_info) == TypeId.Promise); - assertOrPanic(promise_info.Promise.child.? == usize); + expect(TypeId(promise_info) == TypeId.Promise); + expect(promise_info.Promise.child.? == usize); } test "type info: error set, error union info" { @@ -127,15 +127,15 @@ fn testErrorSet() void { }; const error_set_info = @typeInfo(TestErrorSet); - assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet); - assertOrPanic(error_set_info.ErrorSet.errors.len == 3); - assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); - assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); + expect(TypeId(error_set_info) == TypeId.ErrorSet); + expect(error_set_info.ErrorSet.errors.len == 3); + expect(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); + expect(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); const error_union_info = @typeInfo(TestErrorSet!usize); - assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion); - assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet); - assertOrPanic(error_union_info.ErrorUnion.payload == usize); + expect(TypeId(error_union_info) == TypeId.ErrorUnion); + expect(error_union_info.ErrorUnion.error_set == TestErrorSet); + expect(error_union_info.ErrorUnion.payload == usize); } test "type info: enum info" { @@ -152,13 +152,13 @@ fn testEnum() void { }; const os_info = @typeInfo(Os); - assertOrPanic(TypeId(os_info) == TypeId.Enum); - assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(os_info.Enum.fields.len == 4); - assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); - assertOrPanic(os_info.Enum.fields[3].value == 3); - assertOrPanic(os_info.Enum.tag_type == u2); - assertOrPanic(os_info.Enum.defs.len == 0); + expect(TypeId(os_info) == TypeId.Enum); + expect(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + expect(os_info.Enum.fields.len == 4); + expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); + expect(os_info.Enum.fields[3].value == 3); + expect(os_info.Enum.tag_type == u2); + expect(os_info.Enum.defs.len == 0); } test "type info: union info" { @@ -168,14 +168,14 @@ test "type info: union info" { fn testUnion() void { const typeinfo_info = @typeInfo(TypeInfo); - assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); - assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); - assertOrPanic(typeinfo_info.Union.fields.len == 25); - assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); - assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); - assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assertOrPanic(typeinfo_info.Union.defs.len == 21); + 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[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)); + expect(typeinfo_info.Union.defs.len == 21); const TestNoTagUnion = union { Foo: void, @@ -183,22 +183,22 @@ fn testUnion() void { }; const notag_union_info = @typeInfo(TestNoTagUnion); - assertOrPanic(TypeId(notag_union_info) == TypeId.Union); - assertOrPanic(notag_union_info.Union.tag_type == null); - assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(notag_union_info.Union.fields.len == 2); - assertOrPanic(notag_union_info.Union.fields[0].enum_field == null); - assertOrPanic(notag_union_info.Union.fields[1].field_type == u32); + expect(TypeId(notag_union_info) == TypeId.Union); + expect(notag_union_info.Union.tag_type == null); + expect(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + expect(notag_union_info.Union.fields.len == 2); + expect(notag_union_info.Union.fields[0].enum_field == null); + expect(notag_union_info.Union.fields[1].field_type == u32); const TestExternUnion = extern union { foo: *c_void, }; const extern_union_info = @typeInfo(TestExternUnion); - assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); - assertOrPanic(extern_union_info.Union.tag_type == null); - assertOrPanic(extern_union_info.Union.fields[0].enum_field == null); - assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void); + expect(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + expect(extern_union_info.Union.tag_type == null); + expect(extern_union_info.Union.fields[0].enum_field == null); + expect(extern_union_info.Union.fields[0].field_type == *c_void); } test "type info: struct info" { @@ -208,17 +208,17 @@ test "type info: struct info" { fn testStruct() void { const struct_info = @typeInfo(TestStruct); - assertOrPanic(TypeId(struct_info) == TypeId.Struct); - assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); - assertOrPanic(struct_info.Struct.fields.len == 3); - assertOrPanic(struct_info.Struct.fields[1].offset == null); - assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct); - assertOrPanic(struct_info.Struct.defs.len == 2); - assertOrPanic(struct_info.Struct.defs[0].is_pub); - assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); + expect(TypeId(struct_info) == TypeId.Struct); + expect(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + expect(struct_info.Struct.fields.len == 3); + expect(struct_info.Struct.fields[1].offset == null); + expect(struct_info.Struct.fields[2].field_type == *TestStruct); + expect(struct_info.Struct.defs.len == 2); + expect(struct_info.Struct.defs[0].is_pub); + expect(!struct_info.Struct.defs[0].data.Fn.is_extern); + expect(struct_info.Struct.defs[0].data.Fn.lib_name == null); + expect(struct_info.Struct.defs[0].data.Fn.return_type == void); + expect(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); } const TestStruct = packed struct { @@ -238,18 +238,18 @@ test "type info: function type info" { fn testFunction() void { const fn_info = @typeInfo(@typeOf(foo)); - assertOrPanic(TypeId(fn_info) == TypeId.Fn); - assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); - assertOrPanic(fn_info.Fn.is_generic); - assertOrPanic(fn_info.Fn.args.len == 2); - assertOrPanic(fn_info.Fn.is_var_args); - assertOrPanic(fn_info.Fn.return_type == null); - assertOrPanic(fn_info.Fn.async_allocator_type == null); + expect(TypeId(fn_info) == TypeId.Fn); + expect(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); + expect(fn_info.Fn.is_generic); + expect(fn_info.Fn.args.len == 2); + expect(fn_info.Fn.is_var_args); + expect(fn_info.Fn.return_type == null); + expect(fn_info.Fn.async_allocator_type == null); const test_instance: TestStruct = undefined; const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); - assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn); - assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); + expect(TypeId(bound_fn_info) == TypeId.BoundFn); + expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); } fn foo(comptime a: usize, b: bool, args: ...) usize { @@ -270,7 +270,7 @@ test "type info: vectors" { fn testVector() void { const vec_info = @typeInfo(@Vector(4, i32)); - assertOrPanic(TypeId(vec_info) == TypeId.Vector); - assertOrPanic(vec_info.Vector.len == 4); - assertOrPanic(vec_info.Vector.child == i32); + expect(TypeId(vec_info) == TypeId.Vector); + expect(vec_info.Vector.len == 4); + expect(vec_info.Vector.child == i32); } diff --git a/test/stage1/behavior/undefined.zig b/test/stage1/behavior/undefined.zig index 333e217d49..4c233576cd 100644 --- a/test/stage1/behavior/undefined.zig +++ b/test/stage1/behavior/undefined.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; fn initStaticArray() [10]i32 { @@ -11,16 +11,16 @@ fn initStaticArray() [10]i32 { } const static_array = initStaticArray(); test "init static array to undefined" { - assertOrPanic(static_array[0] == 1); - assertOrPanic(static_array[4] == 2); - assertOrPanic(static_array[7] == 3); - assertOrPanic(static_array[9] == 4); + expect(static_array[0] == 1); + expect(static_array[4] == 2); + expect(static_array[7] == 3); + expect(static_array[9] == 4); comptime { - assertOrPanic(static_array[0] == 1); - assertOrPanic(static_array[4] == 2); - assertOrPanic(static_array[7] == 3); - assertOrPanic(static_array[9] == 4); + expect(static_array[0] == 1); + expect(static_array[4] == 2); + expect(static_array[7] == 3); + expect(static_array[9] == 4); } } @@ -40,12 +40,12 @@ test "assign undefined to struct" { comptime { var foo: Foo = undefined; setFooX(&foo); - assertOrPanic(foo.x == 2); + expect(foo.x == 2); } { var foo: Foo = undefined; setFooX(&foo); - assertOrPanic(foo.x == 2); + expect(foo.x == 2); } } @@ -53,17 +53,17 @@ test "assign undefined to struct with method" { comptime { var foo: Foo = undefined; foo.setFooXMethod(); - assertOrPanic(foo.x == 3); + expect(foo.x == 3); } { var foo: Foo = undefined; foo.setFooXMethod(); - assertOrPanic(foo.x == 3); + expect(foo.x == 3); } } test "type name of undefined" { const x = undefined; - assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); + expect(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); } diff --git a/test/stage1/behavior/underscore.zig b/test/stage1/behavior/underscore.zig index 7443319336..fd5aebc87e 100644 --- a/test/stage1/behavior/underscore.zig +++ b/test/stage1/behavior/underscore.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "ignore lval with underscore" { _ = false; diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index c8e8feb11e..0a4e2cfb92 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Value = union(enum) { Int: u64, @@ -27,11 +27,11 @@ const array = []Value{ test "unions embedded in aggregate types" { switch (array[1]) { - Value.Array => |arr| assertOrPanic(arr[4] == 3), + Value.Array => |arr| expect(arr[4] == 3), else => unreachable, } switch ((err catch unreachable).val1) { - Value.Int => |x| assertOrPanic(x == 1234), + Value.Int => |x| expect(x == 1234), else => unreachable, } } @@ -43,18 +43,18 @@ const Foo = union { test "basic unions" { var foo = Foo{ .int = 1 }; - assertOrPanic(foo.int == 1); + expect(foo.int == 1); foo = Foo{ .float = 12.34 }; - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); } test "comptime union field access" { comptime { var foo = Foo{ .int = 0 }; - assertOrPanic(foo.int == 0); + expect(foo.int == 0); foo = Foo{ .float = 42.42 }; - assertOrPanic(foo.float == 42.42); + expect(foo.float == 42.42); } } @@ -62,10 +62,10 @@ test "init union with runtime value" { var foo: Foo = undefined; setFloat(&foo, 12.34); - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); setInt(&foo, 42); - assertOrPanic(foo.int == 42); + expect(foo.int == 42); } fn setFloat(foo: *Foo, x: f64) void { @@ -83,9 +83,9 @@ const FooExtern = extern union { test "basic extern unions" { var foo = FooExtern{ .int = 1 }; - assertOrPanic(foo.int == 1); + expect(foo.int == 1); foo.float = 12.34; - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); } const Letter = enum { @@ -105,11 +105,11 @@ test "union with specified enum tag" { } fn doTest() void { - assertOrPanic(bar(Payload{ .A = 1234 }) == -10); + expect(bar(Payload{ .A = 1234 }) == -10); } fn bar(value: Payload) i32 { - assertOrPanic(Letter(value) == Letter.A); + expect(Letter(value) == Letter.A); return switch (value) { Payload.A => |x| return x - 1244, Payload.B => |x| if (x == 12.34) i32(20) else 21, @@ -125,8 +125,8 @@ const MultipleChoice = union(enum(u32)) { }; test "simple union(enum(u32))" { var x = MultipleChoice.C; - assertOrPanic(x == MultipleChoice.C); - assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60); + expect(x == MultipleChoice.C); + expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60); } const MultipleChoice2 = union(enum(u32)) { @@ -142,14 +142,14 @@ const MultipleChoice2 = union(enum(u32)) { }; test "union(enum(u32)) with specified and unspecified tag values" { - comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32); + comptime expect(@TagType(@TagType(MultipleChoice2)) == u32); testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); - assertOrPanic(1123 == switch (x) { + expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); + expect(1123 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => |v| i32(1000) + v, @@ -167,7 +167,7 @@ const ExternPtrOrInt = extern union { int: u64, }; test "extern union size" { - comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8); + comptime expect(@sizeOf(ExternPtrOrInt) == 8); } const PackedPtrOrInt = packed union { @@ -175,14 +175,14 @@ const PackedPtrOrInt = packed union { int: u64, }; test "extern union size" { - comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8); + comptime expect(@sizeOf(PackedPtrOrInt) == 8); } const ZeroBits = union { OnlyField: void, }; test "union with only 1 field which is void should be zero bits" { - comptime assertOrPanic(@sizeOf(ZeroBits) == 0); + comptime expect(@sizeOf(ZeroBits) == 0); } const TheTag = enum { @@ -196,9 +196,9 @@ const TheUnion = union(TheTag) { C: i32, }; test "union field access gives the enum values" { - assertOrPanic(TheUnion.A == TheTag.A); - assertOrPanic(TheUnion.B == TheTag.B); - assertOrPanic(TheUnion.C == TheTag.C); + expect(TheUnion.A == TheTag.A); + expect(TheUnion.B == TheTag.B); + expect(TheUnion.C == TheTag.C); } test "cast union to tag type of union" { @@ -207,12 +207,12 @@ test "cast union to tag type of union" { } fn testCastUnionToTagType(x: TheUnion) void { - assertOrPanic(TheTag(x) == TheTag.B); + expect(TheTag(x) == TheTag.B); } test "cast tag type of union to union" { var x: Value2 = Letter2.B; - assertOrPanic(Letter2(x) == Letter2.B); + expect(Letter2(x) == Letter2.B); } const Letter2 = enum { A, @@ -227,11 +227,11 @@ const Value2 = union(Letter2) { test "implicit cast union to its tag type" { var x: Value2 = Letter2.B; - assertOrPanic(x == Letter2.B); + expect(x == Letter2.B); giveMeLetterB(x); } fn giveMeLetterB(x: Letter2) void { - assertOrPanic(x == Value2.B); + expect(x == Value2.B); } pub const PackThis = union(enum) { @@ -244,7 +244,7 @@ test "constant packed union" { } fn testConstPackedUnion(expected_tokens: []const PackThis) void { - assertOrPanic(expected_tokens[0].StringLiteral == 1); + expect(expected_tokens[0].StringLiteral == 1); } test "switch on union with only 1 field" { @@ -256,7 +256,7 @@ test "switch on union with only 1 field" { z = PartialInstWithPayload{ .Compiled = 1234 }; switch (z) { PartialInstWithPayload.Compiled => |x| { - assertOrPanic(x == 1234); + expect(x == 1234); return; }, } @@ -282,11 +282,11 @@ test "access a member of tagged union with conflicting enum tag name" { const B = void; }; - comptime assertOrPanic(Bar.A == u8); + comptime expect(Bar.A == u8); } test "tagged union initialization with runtime void" { - assertOrPanic(testTaggedUnionInit({})); + expect(testTaggedUnionInit({})); } const TaggedUnionWithAVoid = union(enum) { @@ -324,9 +324,9 @@ test "union with only 1 field casted to its enum type" { var e = Expr{ .Literal = Literal{ .Bool = true } }; const Tag = @TagType(Expr); - comptime assertOrPanic(@TagType(Tag) == comptime_int); + comptime expect(@TagType(Tag) == comptime_int); var t = Tag(e); - assertOrPanic(t == Expr.Literal); + expect(t == Expr.Literal); } test "union with only 1 field casted to its enum type which has enum value specified" { @@ -344,9 +344,9 @@ test "union with only 1 field casted to its enum type which has enum value speci }; var e = Expr{ .Literal = Literal{ .Bool = true } }; - comptime assertOrPanic(@TagType(Tag) == comptime_int); + comptime expect(@TagType(Tag) == comptime_int); var t = Tag(e); - assertOrPanic(t == Expr.Literal); - assertOrPanic(@enumToInt(t) == 33); - comptime assertOrPanic(@enumToInt(t) == 33); + expect(t == Expr.Literal); + expect(@enumToInt(t) == 33); + comptime expect(@enumToInt(t) == 33); } diff --git a/test/stage1/behavior/var_args.zig b/test/stage1/behavior/var_args.zig index 1f782a3bb3..cc93b57f06 100644 --- a/test/stage1/behavior/var_args.zig +++ b/test/stage1/behavior/var_args.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn add(args: ...) i32 { var sum = i32(0); @@ -12,9 +12,9 @@ fn add(args: ...) i32 { } test "add arbitrary args" { - assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10); - assertOrPanic(add(i32(1234)) == 1234); - assertOrPanic(add() == 0); + expect(add(i32(1), i32(2), i32(3), i32(4)) == 10); + expect(add(i32(1234)) == 1234); + expect(add() == 0); } fn readFirstVarArg(args: ...) void { @@ -26,9 +26,9 @@ test "send void arg to var args" { } test "pass args directly" { - assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); - assertOrPanic(addSomeStuff(i32(1234)) == 1234); - assertOrPanic(addSomeStuff() == 0); + expect(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); + expect(addSomeStuff(i32(1234)) == 1234); + expect(addSomeStuff() == 0); } fn addSomeStuff(args: ...) i32 { @@ -36,24 +36,24 @@ fn addSomeStuff(args: ...) i32 { } test "runtime parameter before var args" { - assertOrPanic(extraFn(10) == 0); - assertOrPanic(extraFn(10, false) == 1); - assertOrPanic(extraFn(10, false, true) == 2); + expect(extraFn(10) == 0); + expect(extraFn(10, false) == 1); + expect(extraFn(10, false, true) == 2); // TODO issue #313 //comptime { - // assertOrPanic(extraFn(10) == 0); - // assertOrPanic(extraFn(10, false) == 1); - // assertOrPanic(extraFn(10, false, true) == 2); + // expect(extraFn(10) == 0); + // expect(extraFn(10, false) == 1); + // expect(extraFn(10, false, true) == 2); //} } fn extraFn(extra: u32, args: ...) usize { if (args.len >= 1) { - assertOrPanic(args[0] == false); + expect(args[0] == false); } if (args.len >= 2) { - assertOrPanic(args[1] == true); + expect(args[1] == true); } return args.len; } @@ -71,8 +71,8 @@ fn foo2(args: ...) bool { } test "array of var args functions" { - assertOrPanic(foos[0]()); - assertOrPanic(!foos[1]()); + expect(foos[0]()); + expect(!foos[1]()); } test "pass zero length array to var args param" { diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index c97ee0e3d6..7cead12b65 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -1,15 +1,15 @@ const std = @import("std"); const mem = std.mem; -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "vector wrap operators" { const S = struct { fn doTheTest() void { const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; - assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); - assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); - assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); + expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); + expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); + expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); } }; S.doTheTest(); diff --git a/test/stage1/behavior/void.zig b/test/stage1/behavior/void.zig index 431d3f4eb1..9722791946 100644 --- a/test/stage1/behavior/void.zig +++ b/test/stage1/behavior/void.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Foo = struct { a: void, @@ -13,14 +13,14 @@ test "compare void with void compile time known" { .b = 1, .c = {}, }; - assertOrPanic(foo.a == {}); + expect(foo.a == {}); } } test "iterate over a void slice" { var j: usize = 0; for (times(10)) |_, i| { - assertOrPanic(i == j); + expect(i == j); j += 1; } } @@ -31,5 +31,5 @@ fn times(n: usize) []const void { test "void optional" { var x: ?void = {}; - assertOrPanic(x != null); + expect(x != null); } diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig index 579b4e4db8..29ad90ed17 100644 --- a/test/stage1/behavior/while.zig +++ b/test/stage1/behavior/while.zig @@ -1,12 +1,12 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "while loop" { var i: i32 = 0; while (i < 4) { i += 1; } - assertOrPanic(i == 4); - assertOrPanic(whileLoop1() == 1); + expect(i == 4); + expect(whileLoop1() == 1); } fn whileLoop1() i32 { return whileLoop2(); @@ -18,7 +18,7 @@ fn whileLoop2() i32 { } test "static eval while" { - assertOrPanic(static_eval_while_number == 1); + expect(static_eval_while_number == 1); } const static_eval_while_number = staticWhileLoop1(); fn staticWhileLoop1() i32 { @@ -32,7 +32,7 @@ fn staticWhileLoop2() i32 { test "continue and break" { runContinueAndBreakTest(); - assertOrPanic(continue_and_break_counter == 8); + expect(continue_and_break_counter == 8); } var continue_and_break_counter: i32 = 0; fn runContinueAndBreakTest() void { @@ -45,7 +45,7 @@ fn runContinueAndBreakTest() void { } break; } - assertOrPanic(i == 4); + expect(i == 4); } test "return with implicit cast from while loop" { @@ -66,7 +66,7 @@ test "while with continue expression" { sum += i; } } - assertOrPanic(sum == 40); + expect(sum == 40); } test "while with else" { @@ -78,8 +78,8 @@ test "while with else" { } else { got_else += 1; } - assertOrPanic(sum == 10); - assertOrPanic(got_else == 1); + expect(sum == 10); + expect(got_else == 1); } test "while with optional as condition" { @@ -88,7 +88,7 @@ test "while with optional as condition" { while (getNumberOrNull()) |value| { sum += value; } - assertOrPanic(sum == 45); + expect(sum == 45); } test "while with optional as condition with else" { @@ -97,12 +97,12 @@ test "while with optional as condition with else" { var got_else: i32 = 0; while (getNumberOrNull()) |value| { sum += value; - assertOrPanic(got_else == 0); + expect(got_else == 0); } else { got_else += 1; } - assertOrPanic(sum == 45); - assertOrPanic(got_else == 1); + expect(sum == 45); + expect(got_else == 1); } test "while with error union condition" { @@ -112,11 +112,11 @@ test "while with error union condition" { while (getNumberOrErr()) |value| { sum += value; } else |err| { - assertOrPanic(err == error.OutOfNumbers); + expect(err == error.OutOfNumbers); got_else += 1; } - assertOrPanic(sum == 45); - assertOrPanic(got_else == 1); + expect(sum == 45); + expect(got_else == 1); } var numbers_left: i32 = undefined; @@ -138,7 +138,7 @@ test "while on optional with else result follow else prong" { break value; } else i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on optional with else result follow break prong" { @@ -146,7 +146,7 @@ test "while on optional with else result follow break prong" { break value; } else i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "while on error union with else result follow else prong" { @@ -154,7 +154,7 @@ test "while on error union with else result follow else prong" { break value; } else |err| i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on error union with else result follow break prong" { @@ -162,7 +162,7 @@ test "while on error union with else result follow break prong" { break value; } else |err| i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "while on bool with else result follow else prong" { @@ -170,7 +170,7 @@ test "while on bool with else result follow else prong" { break i32(10); } else i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on bool with else result follow break prong" { @@ -178,7 +178,7 @@ test "while on bool with else result follow break prong" { break i32(10); } else i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "break from outer while loop" { diff --git a/test/stage1/behavior/widening.zig b/test/stage1/behavior/widening.zig index 7577868aff..f7c238ee8d 100644 --- a/test/stage1/behavior/widening.zig +++ b/test/stage1/behavior/widening.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; test "integer widening" { @@ -9,13 +9,13 @@ test "integer widening" { var d: u64 = c; var e: u64 = d; var f: u128 = e; - assertOrPanic(f == a); + expect(f == a); } test "implicit unsigned integer to signed integer" { var a: u8 = 250; var b: i16 = a; - assertOrPanic(b == 250); + expect(b == 250); } test "float widening" { @@ -23,6 +23,6 @@ test "float widening" { var b: f32 = a; var c: f64 = b; var d: f128 = c; - assertOrPanic(d == a); + expect(d == a); } diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 196311a283..4805fc9896 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; extern fn run_c_tests() void; @@ -33,28 +33,28 @@ test "C ABI integers" { } export fn zig_u8(x: u8) void { - assertOrPanic(x == 0xff); + expect(x == 0xff); } export fn zig_u16(x: u16) void { - assertOrPanic(x == 0xfffe); + expect(x == 0xfffe); } export fn zig_u32(x: u32) void { - assertOrPanic(x == 0xfffffffd); + expect(x == 0xfffffffd); } export fn zig_u64(x: u64) void { - assertOrPanic(x == 0xfffffffffffffffc); + expect(x == 0xfffffffffffffffc); } export fn zig_i8(x: i8) void { - assertOrPanic(x == -1); + expect(x == -1); } export fn zig_i16(x: i16) void { - assertOrPanic(x == -2); + expect(x == -2); } export fn zig_i32(x: i32) void { - assertOrPanic(x == -3); + expect(x == -3); } export fn zig_i64(x: i64) void { - assertOrPanic(x == -4); + expect(x == -4); } extern fn c_f32(f32) void; @@ -66,10 +66,10 @@ test "C ABI floats" { } export fn zig_f32(x: f32) void { - assertOrPanic(x == 12.34); + expect(x == 12.34); } export fn zig_f64(x: f64) void { - assertOrPanic(x == 56.78); + expect(x == 56.78); } extern fn c_ptr(*c_void) void; @@ -79,7 +79,7 @@ test "C ABI pointer" { } export fn zig_ptr(x: *c_void) void { - assertOrPanic(@ptrToInt(x) == 0xdeadbeef); + expect(@ptrToInt(x) == 0xdeadbeef); } extern fn c_bool(bool) void; @@ -89,7 +89,7 @@ test "C ABI bool" { } export fn zig_bool(x: bool) void { - assertOrPanic(x); + expect(x); } extern fn c_array([10]u8) void; @@ -100,7 +100,7 @@ test "C ABI array" { } export fn zig_array(x: [10]u8) void { - assertOrPanic(std.mem.eql(u8, x, "1234567890")); + expect(std.mem.eql(u8, x, "1234567890")); } const BigStruct = extern struct { @@ -124,11 +124,11 @@ test "C ABI big struct" { } export fn zig_big_struct(x: BigStruct) void { - assertOrPanic(x.a == 1); - assertOrPanic(x.b == 2); - assertOrPanic(x.c == 3); - assertOrPanic(x.d == 4); - assertOrPanic(x.e == 5); + expect(x.a == 1); + expect(x.b == 2); + expect(x.c == 3); + expect(x.d == 4); + expect(x.e == 5); } const BigUnion = extern union { @@ -150,11 +150,11 @@ test "C ABI big union" { } export fn zig_big_union(x: BigUnion) void { - assertOrPanic(x.a.a == 1); - assertOrPanic(x.a.b == 2); - assertOrPanic(x.a.c == 3); - assertOrPanic(x.a.d == 4); - assertOrPanic(x.a.e == 5); + expect(x.a.a == 1); + expect(x.a.b == 2); + expect(x.a.c == 3); + expect(x.a.d == 4); + expect(x.a.e == 5); } const SmallStructInts = extern struct { @@ -176,10 +176,10 @@ test "C ABI small struct of ints" { } export fn zig_small_struct_ints(x: SmallStructInts) void { - assertOrPanic(x.a == 1); - assertOrPanic(x.b == 2); - assertOrPanic(x.c == 3); - assertOrPanic(x.d == 4); + expect(x.a == 1); + expect(x.b == 2); + expect(x.c == 3); + expect(x.d == 4); } const SplitStructInt = extern struct { @@ -199,9 +199,9 @@ test "C ABI split struct of ints" { } export fn zig_split_struct_ints(x: SplitStructInt) void { - assertOrPanic(x.a == 1234); - assertOrPanic(x.b == 100); - assertOrPanic(x.c == 1337); + expect(x.a == 1234); + expect(x.b == 100); + expect(x.c == 1337); } extern fn c_big_struct_both(BigStruct) BigStruct; @@ -215,19 +215,19 @@ test "C ABI sret and byval together" { .e = 5, }; var y = c_big_struct_both(s); - assertOrPanic(y.a == 10); - assertOrPanic(y.b == 11); - assertOrPanic(y.c == 12); - assertOrPanic(y.d == 13); - assertOrPanic(y.e == 14); + expect(y.a == 10); + expect(y.b == 11); + expect(y.c == 12); + expect(y.d == 13); + expect(y.e == 14); } export fn zig_big_struct_both(x: BigStruct) BigStruct { - assertOrPanic(x.a == 30); - assertOrPanic(x.b == 31); - assertOrPanic(x.c == 32); - assertOrPanic(x.d == 33); - assertOrPanic(x.e == 34); + expect(x.a == 30); + expect(x.b == 31); + expect(x.c == 32); + expect(x.d == 33); + expect(x.e == 34); var s = BigStruct{ .a = 20, .b = 21, diff --git a/test/standalone/brace_expansion/main.zig b/test/standalone/brace_expansion/main.zig index 52863d5fa4..f5bcd59ecf 100644 --- a/test/standalone/brace_expansion/main.zig +++ b/test/standalone/brace_expansion/main.zig @@ -3,6 +3,7 @@ const io = std.io; const mem = std.mem; const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const Buffer = std.Buffer; const ArrayList = std.ArrayList; const maxInt = std.math.maxInt; @@ -220,11 +221,7 @@ fn expectError(test_input: []const u8, expected_err: anyerror) void { var output_buf = Buffer.initSize(global_allocator, 0) catch unreachable; defer output_buf.deinit(); - if (expandString(test_input, &output_buf)) { - unreachable; - } else |err| { - assert(expected_err == err); - } + testing.expectError(expected_err, expandString(test_input, &output_buf)); } test "valid inputs" { @@ -256,5 +253,5 @@ fn expectExpansion(test_input: []const u8, expected_result: []const u8) void { expandString(test_input, &result) catch unreachable; - assert(mem.eql(u8, result.toSlice(), expected_result)); + testing.expectEqualSlices(u8, expected_result, result.toSlice()); } diff --git a/test/standalone/issue_794/main.zig b/test/standalone/issue_794/main.zig index 356a106418..191bdc9b4f 100644 --- a/test/standalone/issue_794/main.zig +++ b/test/standalone/issue_794/main.zig @@ -1,7 +1,7 @@ const c = @cImport(@cInclude("foo.h")); const std = @import("std"); -const assert = std.debug.assert; +const testing = std.testing; test "c import" { - comptime assert(c.NUMBER == 1234); + comptime testing.expect(c.NUMBER == 1234); } From 46ddd5f5f4db7977010f78129fade7dfa5b9d8d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Feb 2019 19:23:46 -0500 Subject: [PATCH 154/218] fix compiler assertion failure when returning value from test closes #1935 --- src/ir.cpp | 11 +++++++---- test/compile_errors.zig | 7 +++++++ test/tests.zig | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index efda2b321b..d87486bbdd 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11510,10 +11510,13 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio return ir_unreach_error(ira); IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); - if (type_is_invalid(casted_value->value.type) && ira->explicit_return_type_source_node != nullptr) { - ErrorMsg *msg = ira->codegen->errors.last(); - add_error_note(ira->codegen, msg, ira->explicit_return_type_source_node, - buf_sprintf("return type declared here")); + if (type_is_invalid(casted_value->value.type)) { + AstNode *source_node = ira->explicit_return_type_source_node; + if (source_node != nullptr) { + ErrorMsg *msg = ira->codegen->errors.last(); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("return type declared here")); + } return ir_unreach_error(ira); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index acd1eada06..de01a5ac45 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,13 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + 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'", + ); + cases.add( "threadlocal qualifier on const", \\threadlocal const x: i32 = 1234; diff --git a/test/tests.zig b/test/tests.zig index 670c410509..800ddc1ccd 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -538,6 +538,7 @@ pub const CompileErrorContext = struct { expected_errors: ArrayList([]const u8), link_libc: bool, is_exe: bool, + is_test: bool, const SourceFile = struct { filename: []const u8, @@ -596,7 +597,13 @@ pub const CompileErrorContext = struct { var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; - zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj") catch unreachable; + if (self.case.is_exe) { + try zig_args.append("build-exe"); + } else if (self.case.is_test) { + try zig_args.append("test"); + } else { + try zig_args.append("build-obj"); + } zig_args.append(b.pathFromRoot(root_src)) catch unreachable; zig_args.append("--name") catch unreachable; @@ -699,6 +706,7 @@ pub const CompileErrorContext = struct { .expected_errors = ArrayList([]const u8).init(self.b.allocator), .link_libc = false, .is_exe = false, + .is_test = false, }; tc.addSourceFile(".tmp_source.zig", source); @@ -726,6 +734,12 @@ pub const CompileErrorContext = struct { self.addCase(tc); } + pub fn addTest(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void { + const tc = self.create(name, source, expected_lines); + tc.is_test = true; + self.addCase(tc); + } + pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void { const b = self.b; From d6f2af378abe7467657f6fbf8133b995e5f55142 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Feb 2019 19:37:59 -0500 Subject: [PATCH 155/218] fix docs broken by c2db077574be8 --- doc/docgen.zig | 2 +- doc/langref.html.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 7aaf5ebdc7..1bd0805bb9 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -620,7 +620,7 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; const result = try termColor(std.debug.global_allocator, input_bytes); - testing.expectEqualSlices(u8, "AgreenB", result)); + testing.expectEqualSlices(u8, "AgreenB", result); } fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 { diff --git a/doc/langref.html.in b/doc/langref.html.in index e3ba0e3956..2cd35c2f4e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4627,7 +4627,7 @@ test "fibonacci" {

What if we fix the base case, but put the wrong value in the {#syntax#}assert{#endsyntax#} line?

- {#code_begin|test_err|encountered @panic at compile-time#} + {#code_begin|test_err|unable to evaluate constant expression#} const assert = @import("std").debug.assert; fn fibonacci(index: i32) i32 { From 052800e9529a3c2b403b7f43ffba4c981935d0a6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 00:19:06 -0500 Subject: [PATCH 156/218] zig fmt: support threadlocal --- std/zig/ast.zig | 6 +++++ std/zig/parse.zig | 54 +++++++++++++++++++++++++++++++++++++++++ std/zig/parser_test.zig | 8 ++++++ std/zig/render.zig | 3 +++ std/zig/tokenizer.zig | 2 ++ 5 files changed, 73 insertions(+) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index f6ac4ed98c..ea32634566 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -110,6 +110,7 @@ pub const Tree = struct { pub const Error = union(enum) { InvalidToken: InvalidToken, ExpectedVarDeclOrFn: ExpectedVarDeclOrFn, + ExpectedVarDecl: ExpectedVarDecl, ExpectedAggregateKw: ExpectedAggregateKw, UnattachedDocComment: UnattachedDocComment, ExpectedEqOrSemi: ExpectedEqOrSemi, @@ -133,6 +134,7 @@ pub const Error = union(enum) { // TODO https://github.com/ziglang/zig/issues/683 @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream), @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream), + @TagType(Error).ExpectedVarDecl => |*x| return x.render(tokens, stream), @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream), @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream), @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream), @@ -158,6 +160,7 @@ pub const Error = union(enum) { // TODO https://github.com/ziglang/zig/issues/683 @TagType(Error).InvalidToken => |x| return x.token, @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token, + @TagType(Error).ExpectedVarDecl => |x| return x.token, @TagType(Error).ExpectedAggregateKw => |x| return x.token, @TagType(Error).UnattachedDocComment => |x| return x.token, @TagType(Error).ExpectedEqOrSemi => |x| return x.token, @@ -180,6 +183,7 @@ pub const Error = union(enum) { pub const InvalidToken = SingleTokenError("Invalid token {}"); pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}"); + pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found {}"); pub const ExpectedAggregateKw = SingleTokenError("Expected " ++ @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++ @tagName(Token.Id.Keyword_enum) ++ ", found {}"); pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}"); pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}"); @@ -496,6 +500,7 @@ pub const Node = struct { base: Node, doc_comments: ?*DocComment, visib_token: ?TokenIndex, + thread_local_token: ?TokenIndex, name_token: TokenIndex, eq_token: TokenIndex, mut_token: TokenIndex, @@ -536,6 +541,7 @@ pub const Node = struct { pub fn firstToken(self: *const VarDecl) TokenIndex { if (self.visib_token) |visib_token| return visib_token; + if (self.thread_local_token) |thread_local_token| return thread_local_token; if (self.comptime_token) |comptime_token| return comptime_token; if (self.extern_export_token) |extern_export_token| return extern_export_token; assert(self.lib_name == null); diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 783464c620..ae3e00eb4b 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -229,6 +229,32 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { }) catch unreachable; continue; }, + State.ThreadLocal => |ctx| { + const token = nextToken(&tok_it, &tree); + const token_index = token.index; + const token_ptr = token.ptr; + switch (token_ptr.id) { + Token.Id.Keyword_var, Token.Id.Keyword_const => { + try stack.append(State{ + .VarDecl = VarDeclCtx{ + .comments = ctx.comments, + .visib_token = ctx.visib_token, + .thread_local_token = ctx.thread_local_token, + .lib_name = ctx.lib_name, + .comptime_token = ctx.comptime_token, + .extern_export_token = ctx.extern_export_token, + .mut_token = token_index, + .list = ctx.list, + }, + }); + continue; + }, + else => { + ((try tree.errors.addOne())).* = Error{ .ExpectedVarDecl = Error.ExpectedVarDecl{ .token = token_index } }; + return tree; + }, + } + }, State.TopLevelDecl => |ctx| { const token = nextToken(&tok_it, &tree); const token_index = token.index; @@ -260,6 +286,28 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } }); continue; }, + Token.Id.Keyword_threadlocal => { + if (ctx.extern_export_inline_token) |annotated_token| { + if (annotated_token.ptr.id == Token.Id.Keyword_inline) { + ((try tree.errors.addOne())).* = Error{ .InvalidToken = Error.InvalidToken{ .token = annotated_token.index } }; + return tree; + } + } + + try stack.append(State{ + .ThreadLocal = VarDeclCtx{ + .comments = ctx.comments, + .visib_token = ctx.visib_token, + .thread_local_token = token_index, + .lib_name = ctx.lib_name, + .comptime_token = null, + .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null, + .mut_token = undefined, + .list = ctx.decls, + }, + }); + continue; + }, Token.Id.Keyword_var, Token.Id.Keyword_const => { if (ctx.extern_export_inline_token) |annotated_token| { if (annotated_token.ptr.id == Token.Id.Keyword_inline) { @@ -272,6 +320,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .VarDecl = VarDeclCtx{ .comments = ctx.comments, .visib_token = ctx.visib_token, + .thread_local_token = null, .lib_name = ctx.lib_name, .comptime_token = null, .extern_export_token = if (ctx.extern_export_inline_token) |at| at.index else null, @@ -611,6 +660,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .base = ast.Node{ .id = ast.Node.Id.VarDecl }, .doc_comments = ctx.comments, .visib_token = ctx.visib_token, + .thread_local_token = ctx.thread_local_token, .mut_token = ctx.mut_token, .comptime_token = ctx.comptime_token, .extern_export_token = ctx.extern_export_token, @@ -1094,6 +1144,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .VarDecl = VarDeclCtx{ .comments = null, .visib_token = null, + .thread_local_token = null, .comptime_token = null, .extern_export_token = null, .lib_name = null, @@ -1150,6 +1201,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .VarDecl = VarDeclCtx{ .comments = null, .visib_token = null, + .thread_local_token = null, .comptime_token = ctx.comptime_token, .extern_export_token = null, .lib_name = null, @@ -2937,6 +2989,7 @@ const TopLevelDeclCtx = struct { const VarDeclCtx = struct { mut_token: TokenIndex, visib_token: ?TokenIndex, + thread_local_token: ?TokenIndex, comptime_token: ?TokenIndex, extern_export_token: ?TokenIndex, lib_name: ?*ast.Node, @@ -3081,6 +3134,7 @@ const State = union(enum) { ContainerInitArg: *ast.Node.ContainerDecl, ContainerDecl: *ast.Node.ContainerDecl, + ThreadLocal: VarDeclCtx, VarDecl: VarDeclCtx, VarDeclAlign: *ast.Node.VarDecl, VarDeclSection: *ast.Node.VarDecl, diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 7ad842e4b6..93d5ce3437 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,3 +1,10 @@ +test "zig fmt: threadlocal" { + try testCanonical( + \\threadlocal var x: i32 = 1234; + \\ + ); +} + test "zig fmt: linksection" { try testCanonical( \\export var aoeu: u64 linksection(".text.derp") = 1234; @@ -5,6 +12,7 @@ test "zig fmt: linksection" { \\ ); } + test "zig fmt: shebang line" { try testCanonical( \\#!/usr/bin/env zig diff --git a/std/zig/render.zig b/std/zig/render.zig index e55a0beb93..66aba75e1b 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -1706,6 +1706,9 @@ fn renderVarDecl( try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime } + if (var_decl.thread_local_token) |thread_local_token| { + try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal + } try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index e71babe4e8..08ffa28fce 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -53,6 +53,7 @@ pub const Token = struct { Keyword{ .bytes = "switch", .id = Id.Keyword_switch }, Keyword{ .bytes = "test", .id = Id.Keyword_test }, Keyword{ .bytes = "this", .id = Id.Keyword_this }, + Keyword{ .bytes = "threadlocal", .id = Id.Keyword_threadlocal }, Keyword{ .bytes = "true", .id = Id.Keyword_true }, Keyword{ .bytes = "try", .id = Id.Keyword_try }, Keyword{ .bytes = "undefined", .id = Id.Keyword_undefined }, @@ -182,6 +183,7 @@ pub const Token = struct { Keyword_switch, Keyword_test, Keyword_this, + Keyword_threadlocal, Keyword_true, Keyword_try, Keyword_undefined, From a8a63feba7e40a998b1e1d8d36169e5f1be0d4e1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 00:28:12 -0500 Subject: [PATCH 157/218] docgen: update for threadlocal keyword --- doc/docgen.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/docgen.zig b/doc/docgen.zig index 1bd0805bb9..45f6dc2684 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -770,6 +770,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok std.zig.Token.Id.Keyword_suspend, std.zig.Token.Id.Keyword_switch, std.zig.Token.Id.Keyword_test, + std.zig.Token.Id.Keyword_threadlocal, std.zig.Token.Id.Keyword_try, std.zig.Token.Id.Keyword_union, std.zig.Token.Id.Keyword_unreachable, From 0a7bdc00771dbad1dfe5eb93a7cade89059d227a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 14:44:33 -0500 Subject: [PATCH 158/218] implement vector addition with safety checking this would work if @llvm.sadd.with.overflow supported vectors, which it does in trunk. but it does not support them in llvm 7 or even in llvm 8 release branch. so the next commit after this will have to do a different strategy, but when llvm 9 comes out it may be worth coming back to this one. --- src/all_types.hpp | 3 + src/analyze.cpp | 6 +- src/codegen.cpp | 154 ++++++++++++++++++++++++++-------------------- 3 files changed, 95 insertions(+), 68 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 842c9ae904..908c0e327c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1538,6 +1538,8 @@ enum ZigLLVMFnId { ZigLLVMFnIdBitReverse, }; +// There are a bunch of places in code that rely on these values being in +// exactly this order. enum AddSubMul { AddSubMulAdd = 0, AddSubMulSub = 1, @@ -1563,6 +1565,7 @@ struct ZigLLVMFnKey { struct { AddSubMul add_sub_mul; uint32_t bit_count; + uint32_t vector_len; // 0 means not a vector bool is_signed; } overflow_arithmetic; struct { diff --git a/src/analyze.cpp b/src/analyze.cpp index 83a576554a..0c493ebda1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6361,7 +6361,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + - ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820); + ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820) + + x.data.overflow_arithmetic.vector_len * 1435156945; } zig_unreachable(); } @@ -6387,7 +6388,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { case ZigLLVMFnIdOverflowArithmetic: return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) && (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) && - (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed); + (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed) && + (a.data.overflow_arithmetic.vector_len == b.data.overflow_arithmetic.vector_len); } zig_unreachable(); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 3bfd7cdfc5..e45280b0d1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -715,38 +715,59 @@ static void clear_debug_source_node(CodeGen *g) { ZigLLVMClearCurrentDebugLocation(g->builder); } -static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *type_entry, +static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type, const char *signed_name, const char *unsigned_name) { + ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; char fn_name[64]; - assert(type_entry->id == ZigTypeIdInt); - const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name; - sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, type_entry->data.integral.bit_count); + assert(int_type->id == ZigTypeIdInt); + const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name; - LLVMTypeRef return_elem_types[] = { - type_entry->type_ref, - LLVMInt1Type(), - }; LLVMTypeRef param_types[] = { - type_entry->type_ref, - type_entry->type_ref, + operand_type->type_ref, + operand_type->type_ref, }; - LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); - LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - return fn_val; + + if (operand_type->id == ZigTypeIdVector) { + sprintf(fn_name, "llvm.%s.with.overflow.v%" PRIu32 "i%" PRIu32, signed_str, + operand_type->data.vector.len, int_type->data.integral.bit_count); + + LLVMTypeRef return_elem_types[] = { + operand_type->type_ref, + LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len), + }; + LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); + LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); + LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); + assert(LLVMGetIntrinsicID(fn_val)); + return fn_val; + } else { + sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count); + + LLVMTypeRef return_elem_types[] = { + operand_type->type_ref, + LLVMInt1Type(), + }; + LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); + LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); + LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); + assert(LLVMGetIntrinsicID(fn_val)); + return fn_val; + } } -static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubMul add_sub_mul) { - assert(type_entry->id == ZigTypeIdInt); +static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSubMul add_sub_mul) { + ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; + assert(int_type->id == ZigTypeIdInt); ZigLLVMFnKey key = {}; key.id = ZigLLVMFnIdOverflowArithmetic; - key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; + key.data.overflow_arithmetic.is_signed = int_type->data.integral.is_signed; key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; - key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count; + key.data.overflow_arithmetic.bit_count = (uint32_t)int_type->data.integral.bit_count; + key.data.overflow_arithmetic.vector_len = (operand_type->id == ZigTypeIdVector) ? + operand_type->data.vector.len : 0; auto existing_entry = g->llvm_fn_table.maybe_get(key); if (existing_entry) @@ -755,13 +776,13 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubM LLVMValueRef fn_val; switch (add_sub_mul) { case AddSubMulAdd: - fn_val = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd"); + fn_val = get_arithmetic_overflow_fn(g, operand_type, "sadd", "uadd"); break; case AddSubMulSub: - fn_val = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub"); + fn_val = get_arithmetic_overflow_fn(g, operand_type, "ssub", "usub"); break; case AddSubMulMul: - fn_val = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul"); + fn_val = get_arithmetic_overflow_fn(g, operand_type, "smul", "umul"); break; } @@ -1752,17 +1773,28 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z } } -static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *type_entry, AddSubMul op, +static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, LLVMValueRef val1, LLVMValueRef val2) { - LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op); + LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); LLVMValueRef params[] = { val1, val2, }; LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); + + LLVMValueRef overflow_bit; + if (operand_type->id == ZigTypeIdVector) { + LLVMValueRef overflow_vector = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); + LLVMTypeRef bigger_int_type_ref = LLVMIntType(operand_type->data.vector.len); + LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bigger_int_type_ref, ""); + LLVMValueRef zero = LLVMConstNull(bigger_int_type_ref); + overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, ""); + } else { + overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); + } + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); @@ -2608,7 +2640,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, (op_id == IrBinOpAdd || op_id == IrBinOpSub) && op1->value.type->data.pointer.ptr_len == PtrLenUnknown) ); - ZigType *type_entry = op1->value.type; + ZigType *operand_type = op1->value.type; + ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; bool want_runtime_safety = bin_op_instruction->safety_check_on && ir_want_runtime_safety(g, &bin_op_instruction->base); @@ -2634,17 +2667,17 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, case IrBinOpCmpGreaterThan: case IrBinOpCmpLessOrEq: case IrBinOpCmpGreaterOrEq: - if (type_entry->id == ZigTypeIdFloat) { + if (scalar_type->id == ZigTypeIdFloat) { ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); - } else if (type_entry->id == ZigTypeIdInt) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed); + } else if (scalar_type->id == ZigTypeIdInt) { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, scalar_type->data.integral.is_signed); return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else if (type_entry->id == ZigTypeIdEnum || - type_entry->id == ZigTypeIdErrorSet || - type_entry->id == ZigTypeIdBool || - get_codegen_ptr_type(type_entry) != nullptr) + } else if (scalar_type->id == ZigTypeIdEnum || + scalar_type->id == ZigTypeIdErrorSet || + scalar_type->id == ZigTypeIdBool || + get_codegen_ptr_type(scalar_type) != nullptr) { LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); @@ -2665,23 +2698,16 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; - bool is_vector = type_entry->id == ZigTypeIdVector; bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); AddSubMul add_sub_mul = op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : AddSubMulMul; - // The code that is generated for vectors and scalars are the same, - // so we can just set type_entry to the vectors elem_type an avoid - // a lot of repeated code. - if (is_vector) - type_entry = type_entry->data.vector.elem_type; - - if (type_entry->id == ZigTypeIdPointer) { - assert(type_entry->data.pointer.ptr_len == PtrLenUnknown); + if (scalar_type->id == ZigTypeIdPointer) { + assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); LLVMValueRef subscript_value; - if (is_vector) + if (operand_type->id == ZigTypeIdVector) zig_panic("TODO: Implement vector operations on pointers."); switch (add_sub_mul) { @@ -2697,17 +2723,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, // TODO runtime safety return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, ""); - } else if (type_entry->id == ZigTypeIdFloat) { + } else if (scalar_type->id == ZigTypeIdFloat) { ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else if (type_entry->id == ZigTypeIdInt) { + } else if (scalar_type->id == ZigTypeIdInt) { if (is_wrapping) { return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } else if (want_runtime_safety) { - if (is_vector) - zig_panic("TODO: Implement runtime safety vector operations."); - return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value); - } else if (type_entry->data.integral.is_signed) { + return gen_overflow_op(g, operand_type, add_sub_mul, op1_value, op2_value); + } else if (scalar_type->data.integral.is_signed) { return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); } else { return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); @@ -2725,15 +2749,14 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, case IrBinOpBitShiftLeftLossy: case IrBinOpBitShiftLeftExact: { - assert(type_entry->id == ZigTypeIdInt); - LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, - type_entry, op2_value); + assert(scalar_type->id == ZigTypeIdInt); + LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value); bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); if (is_sloppy) { return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); } else if (want_runtime_safety) { - return gen_overflow_shl_op(g, type_entry, op1_value, op2_casted); - } else if (type_entry->data.integral.is_signed) { + return gen_overflow_shl_op(g, scalar_type, op1_value, op2_casted); + } else if (scalar_type->data.integral.is_signed) { return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); } else { return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, ""); @@ -2742,19 +2765,18 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, case IrBinOpBitShiftRightLossy: case IrBinOpBitShiftRightExact: { - assert(type_entry->id == ZigTypeIdInt); - LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, - type_entry, op2_value); + assert(scalar_type->id == ZigTypeIdInt); + LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value); bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); if (is_sloppy) { - if (type_entry->data.integral.is_signed) { + if (scalar_type->data.integral.is_signed) { return LLVMBuildAShr(g->builder, op1_value, op2_casted, ""); } else { return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); } } else if (want_runtime_safety) { - return gen_overflow_shr_op(g, type_entry, op1_value, op2_casted); - } else if (type_entry->data.integral.is_signed) { + return gen_overflow_shr_op(g, scalar_type, op1_value, op2_casted); + } else if (scalar_type->data.integral.is_signed) { return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); } else { return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); @@ -2762,22 +2784,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, } case IrBinOpDivUnspecified: return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, DivKindFloat); + op1_value, op2_value, scalar_type, DivKindFloat); case IrBinOpDivExact: return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, DivKindExact); + op1_value, op2_value, scalar_type, DivKindExact); case IrBinOpDivTrunc: return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, DivKindTrunc); + op1_value, op2_value, scalar_type, DivKindTrunc); case IrBinOpDivFloor: return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, DivKindFloor); + op1_value, op2_value, scalar_type, DivKindFloor); case IrBinOpRemRem: return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, RemKindRem); + op1_value, op2_value, scalar_type, RemKindRem); case IrBinOpRemMod: return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, type_entry, RemKindMod); + op1_value, op2_value, scalar_type, RemKindMod); } zig_unreachable(); } From 373e21bb564a27c4292812bdfd1673711c2e0fe4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 15:23:29 -0500 Subject: [PATCH 159/218] implement vector math safety with ext and trunc --- src/codegen.cpp | 55 +++++++++++++++++++++-------------- test/runtime_safety.zig | 14 +++++++++ test/stage1/behavior/math.zig | 17 +++++++++++ 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index e45280b0d1..4868576b49 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1773,25 +1773,46 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z } } +typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); +// These are lookup table using the AddSubMul enum as the lookup. +// If AddSubMul ever changes, then these tables will be out of +// date. +static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; +static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; +static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; +static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; + static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, LLVMValueRef val1, LLVMValueRef val2) { - LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); - LLVMValueRef params[] = { - val1, - val2, - }; - LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); - LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit; + LLVMValueRef result; + if (operand_type->id == ZigTypeIdVector) { - LLVMValueRef overflow_vector = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - LLVMTypeRef bigger_int_type_ref = LLVMIntType(operand_type->data.vector.len); - LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bigger_int_type_ref, ""); - LLVMValueRef zero = LLVMConstNull(bigger_int_type_ref); + ZigType *int_type = operand_type->data.vector.elem_type; + assert(int_type->id == ZigTypeIdInt); + LLVMTypeRef one_more_bit_int = LLVMIntType(int_type->data.integral.bit_count + 1); + LLVMTypeRef one_more_bit_int_vector = LLVMVectorType(one_more_bit_int, operand_type->data.vector.len); + const auto buildExtFn = int_type->data.integral.is_signed ? LLVMBuildSExt : LLVMBuildZExt; + LLVMValueRef extended1 = buildExtFn(g->builder, val1, one_more_bit_int_vector, ""); + LLVMValueRef extended2 = buildExtFn(g->builder, val2, one_more_bit_int_vector, ""); + LLVMValueRef extended_result = wrap_op[op](g->builder, extended1, extended2, ""); + result = LLVMBuildTrunc(g->builder, extended_result, operand_type->type_ref, ""); + + LLVMValueRef re_extended_result = buildExtFn(g->builder, result, one_more_bit_int_vector, ""); + LLVMValueRef overflow_vector = LLVMBuildICmp(g->builder, LLVMIntNE, extended_result, re_extended_result, ""); + LLVMTypeRef bitcast_int_type = LLVMIntType(operand_type->data.vector.len); + LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bitcast_int_type, ""); + LLVMValueRef zero = LLVMConstNull(bitcast_int_type); overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, ""); } else { + LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); + LLVMValueRef params[] = { + val1, + val2, + }; + LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); + result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); } @@ -2623,8 +2644,6 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast } -typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); - static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, IrInstructionBinOp *bin_op_instruction) { @@ -2690,14 +2709,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, case IrBinOpAddWrap: case IrBinOpSub: case IrBinOpSubWrap: { - // These are lookup table using the AddSubMul enum as the lookup. - // If AddSubMul ever changes, then these tables will be out of - // date. - static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; - static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; - static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; - static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; - bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); AddSubMul add_sub_mul = op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 7de43b45f4..821328b7a6 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -94,6 +94,20 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + cases.addRuntimeSafety("vector integer addition overflow", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var a: @Vector(4, i32) = []i32{ 1, 2, 2147483643, 4 }; + \\ var b: @Vector(4, i32) = []i32{ 5, 6, 7, 8 }; + \\ const x = add(a, b); + \\} + \\fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { + \\ return a + b; + \\} + ); + cases.addRuntimeSafety("integer subtraction overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index 0b88cc4497..36e81e11ed 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -1,5 +1,7 @@ const std = @import("std"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectEqualSlices = std.testing.expectEqualSlices; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -498,3 +500,18 @@ test "comptime_int param and return" { fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { return a + b; } + +test "vector integer addition" { + const S = struct { + fn doTheTest() void { + var a: @Vector(4, i32) = []i32{ 1, 2, 3, 4 }; + var b: @Vector(4, i32) = []i32{ 5, 6, 7, 8 }; + var result = a + b; + var result_array: [4]i32 = result; + const expected = []i32{ 6, 8, 10, 12 }; + expectEqualSlices(i32, &expected, &result_array); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From 34eb9f18acc2370973adcc7be0d010d62300e9a9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 20:41:26 -0500 Subject: [PATCH 160/218] fix not updating debug info type of optional error sets There's an unfortunate footgun in the current design of error sets. The debug info type for every error set is the same as the debug info type of the global error set, which is essentially an enum forward declaration. The problem is that when we "replace" the forward declaration with the final value, once we know all the possible errors, we have to update the pointers of every error set. So the footgun is that if you ever copy the debug info type of the global error set, you have to add the address of the pointer to a list of pointers that need to be updated once we "replace" the forward declaration. I activated the footgun when I introduced the optimization that `?anyerror` types are the same size as `anyerror` types (using 0 as the null value), because I introduced a pointer copy of the global error set debug info type, but forgot to add it to the list. I'm sure that there is a better way to code this, which does not have the footgun, but this commit contains only a fix, not a reworking of the logic. closes #1937 --- src/analyze.cpp | 3 +++ test/stage1/behavior/error.zig | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 0c493ebda1..970d1cc382 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -594,6 +594,9 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { // function types are technically pointers entry->type_ref = child_type->type_ref; entry->di_type = child_type->di_type; + if (entry->di_type == g->builtin_types.entry_global_error_set->di_type) { + g->error_di_types.append(&entry->di_type); + } } else { assert(child_type->di_type); // create a struct with a boolean whether this is the null value diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index 265ddd9d6c..7d9dae7bdd 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -330,3 +330,8 @@ test "optional error set is the same size as error set" { expect(S.returnsOptErrSet() == null); comptime expect(S.returnsOptErrSet() == null); } + +test "debug info for optional error set" { + const SomeError = error{Hello}; + var a_local_variable: ?SomeError = null; +} From 31be1ddf09fafae270d9946a3f09aa25816dd153 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 20:57:45 -0500 Subject: [PATCH 161/218] docs: add threadlocal keyword to grammar --- doc/langref.html.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 2cd35c2f4e..dfea8e1e04 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7870,7 +7870,7 @@ TopLevelComptime <- KEYWORD_comptime BlockExpr TopLevelDecl <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) - / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? VarDecl + / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl / KEYWORD_use Expr SEMICOLON FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) @@ -8330,6 +8330,7 @@ KEYWORD_struct <- 'struct' end_of_word KEYWORD_suspend <- 'suspend' end_of_word KEYWORD_switch <- 'switch' end_of_word KEYWORD_test <- 'test' end_of_word +KEYWORD_threadlocal <- 'threadlocal' end_of_word KEYWORD_true <- 'true' end_of_word KEYWORD_try <- 'try' end_of_word KEYWORD_undefined <- 'undefined' end_of_word @@ -8350,7 +8351,7 @@ keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm / KEYWORD_orelse / KEYWORD_packed / KEYWORD_promise / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection / KEYWORD_stdcallcc / KEYWORD_struct / KEYWORD_suspend - / KEYWORD_switch / KEYWORD_test / KEYWORD_true / KEYWORD_try + / KEYWORD_switch / KEYWORD_test / KEYWORD_threadlocal / KEYWORD_true / KEYWORD_try / KEYWORD_undefined / KEYWORD_union / KEYWORD_unreachable / KEYWORD_use / KEYWORD_var / KEYWORD_volatile / KEYWORD_while {#header_close#} From caf672c49586f1af5e3d41ae200aded991b8b0f7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 21:10:59 -0500 Subject: [PATCH 162/218] `@truncate`: comptime 0 when target type is 0 bits also if the dest type is a comptime_int, then treat it as an implicit cast. also compile error for attempting to truncate undefined closes #1568 --- doc/langref.html.in | 11 +++++++---- src/ir.cpp | 24 ++++++++++++++++-------- test/compile_errors.zig | 11 ++++++++++- test/stage1/behavior/truncate.zig | 23 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index dfea8e1e04..779eb6a31b 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6381,14 +6381,14 @@ fn List(comptime T: type) type { {#header_close#} {#header_open|@truncate#} -
{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}
+
{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}

This function truncates bits from an integer type, resulting in a smaller integer type.

- The following produces a crash in debug mode and undefined behavior in - release mode: + The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in + {#link|ReleaseFast#} mode:

{#syntax#}const a: u16 = 0xabcd;
 const b: u8 = u8(a);{#endsyntax#}
@@ -6402,7 +6402,10 @@ const b: u8 = @truncate(u8, a); This function always truncates the significant bits of the integer, regardless of endianness on the target platform.

- +

+ If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, + then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}. +

{#header_close#} {#header_open|@typeId#} diff --git a/src/ir.cpp b/src/ir.cpp index d87486bbdd..5d4013b4b9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18491,7 +18491,22 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (src_type->data.integral.bit_count == 0) { + if (dest_type->id == ZigTypeIdComptimeInt) { + return ir_implicit_cast(ira, target, dest_type); + } + + if (instr_is_comptime(target)) { + ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint, + dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); + return result; + } + + if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) { IrInstruction *result = ir_const(ira, &instruction->base, dest_type); bigint_init_unsigned(&result->value.data.x_bigint, 0); return result; @@ -18507,13 +18522,6 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (target->value.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - bigint_truncate(&result->value.data.x_bigint, &target->value.data.x_bigint, - dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); - return result; - } - IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope, instruction->base.source_node, dest_type_value, target); new_instruction->value.type = dest_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index de01a5ac45..b47cdf2ed1 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "@truncate undefined value", + \\export fn entry() void { + \\ var z = @truncate(u8, u16(undefined)); + \\} + , + ".tmp_source.zig:2:30: error: use of undefined value", + ); + cases.addTest( "return invalid type from test", \\test "example" { return 1; } @@ -3335,7 +3344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "truncate sign mismatch", \\fn f() i8 { - \\ const x: u32 = 10; + \\ var x: u32 = 10; \\ return @truncate(i8, x); \\} \\ diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig index c195b64cbf..568346369f 100644 --- a/test/stage1/behavior/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -6,3 +6,26 @@ test "truncate u0 to larger integer allowed and has comptime known result" { const y = @truncate(u8, x); comptime expect(y == 0); } + +test "truncate.u0.literal" { + var z = @truncate(u0, 0); + expect(z == 0); +} + +test "truncate.u0.const" { + const c0: usize = 0; + var z = @truncate(u0, c0); + expect(z == 0); +} + +test "truncate.u0.var" { + var d: u8 = 2; + var z = @truncate(u0, d); + expect(z == 0); +} + +test "truncate sign mismatch but comptime known so it works anyway" { + const x: u32 = 10; + var result = @truncate(i8, x); + expect(result == 10); +} From b8cbe3872e702ab8ec388e75cb711330a45825b0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 00:14:30 -0500 Subject: [PATCH 163/218] added C pointer type and implicit int-to-ptr for this type See #1059 --- src/all_types.hpp | 1 + src/analyze.cpp | 14 +- src/ir.cpp | 262 ++++++++++++++++++++---------- src/parser.cpp | 8 + src/tokenizer.cpp | 19 ++- src/tokenizer.hpp | 1 + test/stage1/behavior/pointers.zig | 6 + 7 files changed, 223 insertions(+), 88 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 908c0e327c..fd66b77ad2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1038,6 +1038,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); enum PtrLen { PtrLenUnknown, PtrLenSingle, + PtrLenC, }; struct ZigTypePointer { diff --git a/src/analyze.cpp b/src/analyze.cpp index 970d1cc382..e561050e0d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -417,6 +417,18 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { return entry; } +static const char *ptr_len_to_star_str(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return "*"; + case PtrLenUnknown: + return "[*]"; + case PtrLenC: + return "[*c]"; + } + zig_unreachable(); +} + ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) @@ -466,7 +478,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]"; + const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; buf_resize(&entry->name, 0); diff --git a/src/ir.cpp b/src/ir.cpp index 5d4013b4b9..76277f541b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -169,6 +169,10 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); +static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, + ZigType *ptr_type); +static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *dest_type); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -5019,10 +5023,23 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction * return ir_build_ref(irb, scope, value->source_node, value, false, false); } +static PtrLen star_token_to_ptr_len(TokenId token_id) { + switch (token_id) { + case TokenIdStar: + case TokenIdStarStar: + return PtrLenSingle; + case TokenIdBracketStarBracket: + return PtrLenUnknown; + case TokenIdBracketStarCBracket: + return PtrLenC; + default: + zig_unreachable(); + } +} + static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypePointerType); - PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar || - node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown; + PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id); bool is_const = node->data.pointer_type.is_const; bool is_volatile = node->data.pointer_type.is_volatile; AstNode *expr_node = node->data.pointer_type.op_expr; @@ -8538,6 +8555,20 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } } } + if (other_type->id == ZigTypeIdPointer && other_type->data.pointer.ptr_len == PtrLenC && const_val_is_int) { + if (!bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, true) && + !bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, false)) + { + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); + + ir_add_error(ira, instruction, + buf_sprintf("integer value %s outside of pointer address range", + buf_ptr(val_buf))); + return false; + } + return true; + } const char *num_lit_str; Buf *val_buf = buf_alloc(); @@ -10811,6 +10842,37 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * return ir_build_vector_to_array(ira, source_instr, vector, array_type); } +static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *integer, ZigType *dest_type) +{ + IrInstruction *unsigned_integer; + if (instr_is_comptime(integer)) { + unsigned_integer = integer; + } else { + assert(integer->value.type->id == ZigTypeIdInt); + + if (integer->value.type->data.integral.bit_count > + ira->codegen->builtin_types.entry_usize->data.integral.bit_count) + { + ir_add_error(ira, source_instr, + buf_sprintf("integer type too big for implicit @intToPtr to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (integer->value.type->data.integral.is_signed) { + ZigType *unsigned_int_type = get_int_type(ira->codegen, false, + integer->value.type->data.integral.bit_count); + unsigned_integer = ir_analyze_bit_cast(ira, source_instr, integer, unsigned_int_type); + if (type_is_invalid(unsigned_integer->value.type)) + return ira->codegen->invalid_instruction; + } else { + unsigned_integer = integer; + } + } + + return ir_analyze_int_to_ptr(ira, source_instr, unsigned_integer, dest_type); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, ZigType *wanted_type, IrInstruction *value) { @@ -11217,6 +11279,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); } + // casting to C pointers + if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC) { + // cast from integer to C pointer + if (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt) { + return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); + } + } + // cast from undefined to anything if (actual_type->id == ZigTypeIdUndefined) { return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); @@ -20674,17 +20744,38 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { - Error err; - IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_instruction; +static bool type_can_bit_cast(ZigType *t) { + switch (t->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdMetaType: + case ZigTypeIdOpaque: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdNamespace: + case ZigTypeIdUnreachable: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdPointer: + return false; + default: + // TODO list these types out explicitly, there are probably some other invalid ones here + return true; + } +} + +static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *dest_type) +{ + Error err; - IrInstruction *value = instruction->value->child; ZigType *src_type = value->value.type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_instruction; + assert(get_codegen_ptr_type(src_type) == nullptr); + assert(type_can_bit_cast(src_type)); + assert(get_codegen_ptr_type(dest_type) == nullptr); + assert(type_can_bit_cast(dest_type)); if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; @@ -20692,60 +20783,11 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - if (get_codegen_ptr_type(src_type) != nullptr) { - ir_add_error(ira, value, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - switch (src_type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdNamespace: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - default: - break; - } - - if (get_codegen_ptr_type(dest_type) != nullptr) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - - switch (dest_type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdNamespace: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - default: - break; - } uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); uint64_t src_size_bytes = type_size(ira->codegen, src_type); if (dest_size_bytes != src_size_bytes) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64, buf_ptr(&dest_type->name), dest_size_bytes, buf_ptr(&src_type->name), src_size_bytes)); @@ -20755,7 +20797,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); if (dest_size_bits != src_size_bits) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", buf_ptr(&dest_type->name), dest_size_bits, buf_ptr(&src_type->name), src_size_bits)); @@ -20767,20 +20809,86 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + IrInstruction *result = ir_const(ira, source_instr, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value))) + if ((err = buf_read_value_bytes(ira, ira->codegen, source_instr->source_node, buf, &result->value))) return ira->codegen->invalid_instruction; return result; } - IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, nullptr, value); + IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope, + source_instr->source_node, nullptr, value); result->value.type = dest_type; return result; } +static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { + IrInstruction *dest_type_value = instruction->dest_type->child; + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *value = instruction->value->child; + ZigType *src_type = value->value.type; + if (type_is_invalid(src_type)) + return ira->codegen->invalid_instruction; + + if (get_codegen_ptr_type(src_type) != nullptr) { + ir_add_error(ira, value, + buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(src_type)) { + ir_add_error(ira, dest_type_value, + buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); + return ira->codegen->invalid_instruction; + } + + if (get_codegen_ptr_type(dest_type) != nullptr) { + ir_add_error(ira, dest_type_value, + buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(dest_type)) { + ir_add_error(ira, dest_type_value, + buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type); +} + +static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, + ZigType *ptr_type) +{ + assert(get_src_ptr_type(ptr_type) != nullptr); + assert(type_has_bits(ptr_type)); + + IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); + if (type_is_invalid(casted_int->value.type)) + return ira->codegen->invalid_instruction; + + if (instr_is_comptime(casted_int)) { + ConstExprValue *val = ir_resolve_const(ira, casted_int, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, source_instr, ptr_type); + result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; + result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); + return result; + } + + IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, nullptr, casted_int); + result->value.type = ptr_type; + return result; +} + static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; @@ -20802,30 +20910,12 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru return ira->codegen->invalid_instruction; } + IrInstruction *target = instruction->target->child; if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); - if (type_is_invalid(casted_int->value.type)) - return ira->codegen->invalid_instruction; - - if (instr_is_comptime(casted_int)) { - ConstExprValue *val = ir_resolve_const(ira, casted_int, UndefBad); - if (!val) - return ira->codegen->invalid_instruction; - - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; - result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); - return result; - } - - IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, nullptr, casted_int); - result->value.type = dest_type; - return result; + return ir_analyze_int_to_ptr(ira, &instruction->base, target, dest_type); } static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, diff --git a/src/parser.cpp b/src/parser.cpp index 1c1af87c51..160a7268b0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2779,6 +2779,7 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { // <- ASTERISK // / ASTERISK2 // / LBRACKET ASTERISK RBRACKET +// / LBRACKET ASTERISK C RBRACKET static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { Token *asterisk = eat_token_if(pc, TokenIdStar); if (asterisk != nullptr) { @@ -2804,6 +2805,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { return res; } + Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket); + if (cptr != nullptr) { + AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr); + res->data.pointer_type.star_token = cptr; + return res; + } + return nullptr; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 3acd605748..9ff6ed3bbe 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -221,6 +221,7 @@ enum TokenizeState { TokenizeStateError, TokenizeStateLBracket, TokenizeStateLBracketStar, + TokenizeStateLBracketStarC, }; @@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case '*': t.state = TokenizeStateLBracketStar; - set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket); break; default: // reinterpret as just an lbracket @@ -857,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) { } break; case TokenizeStateLBracketStar: + switch (c) { + case 'c': + t.state = TokenizeStateLBracketStarC; + set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket); + break; + case ']': + set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket); + end_token(&t); + t.state = TokenizeStateStart; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeStateLBracketStarC: switch (c) { case ']': end_token(&t); @@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateLineStringContinue: case TokenizeStateLineStringContinueC: case TokenizeStateLBracketStar: + case TokenizeStateLBracketStarC: tokenize_error(&t, "unexpected EOF"); break; case TokenizeStateLineComment: @@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) { case TokenIdBitShiftRightEq: return ">>="; case TokenIdBitXorEq: return "^="; case TokenIdBracketStarBracket: return "[*]"; + case TokenIdBracketStarCBracket: return "[*c]"; case TokenIdCharLiteral: return "CharLiteral"; case TokenIdCmpEq: return "=="; case TokenIdCmpGreaterOrEq: return ">="; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 17f36699b3..62117b5779 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -29,6 +29,7 @@ enum TokenId { TokenIdBitShiftRightEq, TokenIdBitXorEq, TokenIdBracketStarBracket, + TokenIdBracketStarCBracket, TokenIdCharLiteral, TokenIdCmpEq, TokenIdCmpGreaterOrEq, diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 47b19700ee..6969e151df 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -42,3 +42,9 @@ test "double pointer parsing" { fn PtrOf(comptime T: type) type { return *T; } + +test "assigning integer to C pointer" { + var x: i32 = 0; + var ptr: [*c]u8 = 0; + var ptr2: [*c]u8 = x; +} From 73e8e46257ac8f34e941a357a860d19e0d38dbac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 01:11:30 -0500 Subject: [PATCH 164/218] casting between C pointers and normal pointers See #1059 --- src/ir.cpp | 41 +++++++++++++++++++------------ test/stage1/behavior/pointers.zig | 8 ++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 76277f541b..30350d75de 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2462,7 +2462,7 @@ static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode * ir_ref_instruction(type_value, irb->current_basic_block); - return &instruction->base; + return &instruction->base; } static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, @@ -6739,7 +6739,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode atomic_state_field_name); // set the is_canceled bit - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, is_canceled_mask, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); @@ -6817,7 +6817,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode atomic_state_field_name); // clear the is_suspended bit - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr, AtomicRmwOp_and, AtomicOrderSeqCst); @@ -6933,7 +6933,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle); IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false); - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); @@ -6976,7 +6976,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block); - IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false); @@ -7008,7 +7008,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, cleanup_block); IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false); - IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false); @@ -11279,12 +11279,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); } - // casting to C pointers - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC) { - // cast from integer to C pointer - if (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt) { - return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); - } + // casting between C pointers and normal pointers + if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer && + (wanted_type->data.pointer.ptr_len == PtrLenC || actual_type->data.pointer.ptr_len == PtrLenC) && + types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + actual_type->data.pointer.child_type, source_node, + !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + } + + // cast from integer to C pointer + if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && + (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt)) + { + return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); } // cast from undefined to anything @@ -16436,7 +16445,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, pointee_val = const_ptr_pointee(ira, ira->codegen, &target_value_ptr->value, target_value_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; - + if (pointee_val->special == ConstValSpecialRuntime) pointee_val = nullptr; } @@ -17186,7 +17195,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) @@ -17360,7 +17369,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco // Loop through the definitions and generate info. decl_it = decls_scope->decl_table.entry_iterator(); - curr_entry = nullptr; + curr_entry = nullptr; int definition_index = 0; while ((curr_entry = decl_it.next()) != nullptr) { // Skip comptime blocks and test functions. @@ -20312,7 +20321,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, } else { seenFalse += 1; } - + if ((seenTrue > 1) || (seenFalse > 1)) { ir_add_error(ira, value, buf_sprintf("duplicate switch value")); return ira->codegen->invalid_instruction; diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 6969e151df..79832bc316 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -48,3 +48,11 @@ test "assigning integer to C pointer" { var ptr: [*c]u8 = 0; var ptr2: [*c]u8 = x; } + +test "implicit cast single item pointer to C pointer and back" { + var y: u8 = 11; + var x: [*c]u8 = &y; + var z: *u8 = x; + z.* += 1; + expect(y == 12); +} From 2f9fedabf0805a47aba5c348e5369c1c28f6cf21 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 10 Feb 2019 12:43:49 +0100 Subject: [PATCH 165/218] testing.expectEqual use expected type as the type of actual This allows for impl casts --- std/testing.zig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/std/testing.zig b/std/testing.zig index ade6e8b0dd..bece76ee5c 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -24,11 +24,7 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void { /// equal, prints diagnostics to stderr to show exactly how they are not equal, /// then aborts. /// The types must match exactly. -pub fn expectEqual(expected: var, actual: var) void { - if (@typeOf(actual) != @typeOf(expected)) { - @compileError("type mismatch. expected " ++ @typeName(@typeOf(expected)) ++ ", found " ++ @typeName(@typeOf(actual))); - } - +pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { switch (@typeInfo(@typeOf(actual))) { TypeId.NoReturn, TypeId.BoundFn, From 8e68d43ad373e643797209d59e6f10aa12b4c038 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 10:58:00 -0500 Subject: [PATCH 166/218] avoid needlessly creating global constants This deletes some legacy cruft, and produces leaner object files. Example: ``` var x: i32 = 1234; export fn entry() i32 { return x; } ``` This produces: ``` @x = internal unnamed_addr global i32 1234, align 4 @0 = internal unnamed_addr constant i32* @x, align 8 ``` and @0 is never even used. After this commit, @0 is not produced. This fixes a bug: Zig was creating invalid LLVM IR when one of these globals that shouldn't exist takes the address of a thread local variable. In LLVM 8.0.0rc2, it would produce a linker error. But probably after my bug report is solved it will be caught by the IR verifier. https://bugs.llvm.org/show_bug.cgi?id=40652 --- src/codegen.cpp | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 4868576b49..192c0f0519 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5762,81 +5762,71 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con zig_unreachable(); case ConstPtrSpecialRef: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; render_const_val(g, pointee, ""); render_const_val_global(g, pointee, ""); - ConstExprValue *other_val = pointee; - const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref); - render_const_val_global(g, const_val, ""); + const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global, const_val->type->type_ref); return const_val->global_refs->llvm_value; } case ConstPtrSpecialBaseArray: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; assert(array_const_val->type->id == ZigTypeIdArray); - if (array_const_val->type->zero_bits) { + if (!type_has_bits(array_const_val->type)) { // make this a null pointer ZigType *usize = g->builtin_types.entry_usize; const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); return const_val->global_refs->llvm_value; } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, - elem_index); + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); return ptr_val; } case ConstPtrSpecialBaseStruct: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; assert(struct_const_val->type->id == ZigTypeIdStruct); - if (struct_const_val->type->zero_bits) { + if (!type_has_bits(struct_const_val->type)) { // make this a null pointer ZigType *usize = g->builtin_types.entry_usize; const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); return const_val->global_refs->llvm_value; } size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; - size_t gen_field_index = - struct_const_val->type->data.structure.fields[src_field_index].gen_index; + size_t gen_field_index = struct_const_val->type->data.structure.fields[src_field_index].gen_index; LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, gen_field_index); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); return ptr_val; } case ConstPtrSpecialBaseErrorUnionCode: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); - if (err_union_const_val->type->zero_bits) { + if (!type_has_bits(err_union_const_val->type)) { // make this a null pointer ZigType *usize = g->builtin_types.entry_usize; const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); return const_val->global_refs->llvm_value; } LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); return ptr_val; } case ConstPtrSpecialBaseErrorUnionPayload: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); if (err_union_const_val->type->zero_bits) { @@ -5844,18 +5834,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con ZigType *usize = g->builtin_types.entry_usize; const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); return const_val->global_refs->llvm_value; } LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); return ptr_val; } case ConstPtrSpecialBaseOptionalPayload: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; assert(optional_const_val->type->id == ZigTypeIdOptional); if (optional_const_val->type->zero_bits) { @@ -5863,23 +5851,20 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con ZigType *usize = g->builtin_types.entry_usize; const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); return const_val->global_refs->llvm_value; } LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); return ptr_val; } case ConstPtrSpecialHardCodedAddr: { - render_const_val_global(g, const_val, name); + assert(const_val->global_refs != nullptr); uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; ZigType *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); + const_val->global_refs->llvm_value = LLVMConstIntToPtr( + LLVMConstInt(usize->type_ref, addr_value, false), const_val->type->type_ref); return const_val->global_refs->llvm_value; } case ConstPtrSpecialFunction: From 661fc79fba242f2ad72ede06d4e23e635a1b1452 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 12:02:38 -0500 Subject: [PATCH 167/218] langref: update grammar with c pointers See #1059 --- doc/langref.html.in | 7 +++++-- src/parser.cpp | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 779eb6a31b..82ec13c9bb 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8164,7 +8164,8 @@ ArrayTypeStart <- LBRACKET Expr? RBRACKET PtrTypeStart <- ASTERISK / ASTERISK2 - / LBRACKET ASTERISK RBRACKET + / PTRUNKNOWN + / PTRC # ContainerDecl specific ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE @@ -8262,7 +8263,7 @@ LARROW2 <- '<<' ![=] skip LARROW2EQUAL <- '<<=' skip LARROWEQUAL <- '<=' skip LBRACE <- '{' skip -LBRACKET <- '[' skip +LBRACKET <- '[' ![*] skip LPAREN <- '(' skip MINUS <- '-' ![%=>] skip MINUSEQUAL <- '-=' skip @@ -8279,6 +8280,8 @@ PLUS2 <- '++' skip PLUSEQUAL <- '+=' skip PLUSPERCENT <- '+%' ![=] skip PLUSPERCENTEQUAL <- '+%=' skip +PTRC <- '[*c]' skip +PTRUNKNOWN <- '[*]' skip QUESTIONMARK <- '?' skip RARROW <- '>' ![>=] skip RARROW2 <- '>>' ![=] skip diff --git a/src/parser.cpp b/src/parser.cpp index 160a7268b0..3a6ce04647 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2778,8 +2778,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { // PtrTypeStart // <- ASTERISK // / ASTERISK2 -// / LBRACKET ASTERISK RBRACKET -// / LBRACKET ASTERISK C RBRACKET +// / PTRUNKNOWN +// / PTRC static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { Token *asterisk = eat_token_if(pc, TokenIdStar); if (asterisk != nullptr) { From 43df49cb35349e48b63356eef4a990c2233ec88f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 12:59:33 -0500 Subject: [PATCH 168/218] README: move i386-macosx to Tier 4 See #1930 --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e9756b404d..8b64d75c11 100644 --- a/README.md +++ b/README.md @@ -84,13 +84,16 @@ clarity. * LLVM may have the target as an experimental target, which means that you need to use Zig-provided binaries for the target to be available, or build LLVM from source with special configure flags. + * This target may be considered deprecated by an official party, + [such as macosx/i386](https://support.apple.com/en-us/HT208436) in which + case this target will remain forever stuck in Tier 4. #### Support Table | | freestanding | linux | macosx | windows | freebsd | UEFI | other | |--------|--------------|--------|--------|---------|---------|--------|--------| |x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 | -|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | +|i386 | Tier 2 | Tier 2 | Tier 4 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | |arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | |arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | |bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | From 4a1b910e03f931b7d8d3cb8c810b084e6e152e18 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 14:07:19 -0500 Subject: [PATCH 169/218] zig fmt: support C pointers See #1059 --- std/zig/parse.zig | 7 ++++++- std/zig/parser_test.zig | 7 +++++++ std/zig/tokenizer.zig | 23 ++++++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/std/zig/parse.zig b/std/zig/parse.zig index ae3e00eb4b..867dd11592 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -3525,7 +3525,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} }, Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} }, Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddressOf = void{} }, - Token.Id.Asterisk, Token.Id.AsteriskAsterisk, Token.Id.BracketStarBracket => ast.Node.PrefixOp.Op{ + + Token.Id.Asterisk, + Token.Id.AsteriskAsterisk, + Token.Id.BracketStarBracket, + Token.Id.BracketStarCBracket, + => ast.Node.PrefixOp.Op{ .PtrType = ast.Node.PrefixOp.PtrInfo{ .align_info = null, .const_token = null, diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 93d5ce3437..5b7b7aa2a9 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,3 +1,10 @@ +test "zig fmt: C pointers" { + try testCanonical( + \\const Ptr = [*c]i32; + \\ + ); +} + test "zig fmt: threadlocal" { try testCanonical( \\threadlocal var x: i32 = 1234; diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 08ffa28fce..877e4e8db3 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -141,6 +141,7 @@ pub const Token = struct { LineComment, DocComment, BracketStarBracket, + BracketStarCBracket, ShebangLine, Keyword_align, Keyword_and, @@ -279,6 +280,7 @@ pub const Tokenizer = struct { SawAtSign, LBracket, LBracketStar, + LBracketStarC, }; pub fn next(self: *Tokenizer) Token { @@ -456,6 +458,9 @@ pub const Tokenizer = struct { }, State.LBracketStar => switch (c) { + 'c' => { + state = State.LBracketStarC; + }, ']' => { result.id = Token.Id.BracketStarBracket; self.index += 1; @@ -467,6 +472,18 @@ pub const Tokenizer = struct { }, }, + State.LBracketStarC => switch (c) { + ']' => { + result.id = Token.Id.BracketStarCBracket; + self.index += 1; + break; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.Ampersand => switch (c) { '=' => { result.id = Token.Id.AmpersandEqual; @@ -1035,6 +1052,7 @@ pub const Tokenizer = struct { State.CharLiteralEnd, State.StringLiteralBackslash, State.LBracketStar, + State.LBracketStarC, => { result.id = Token.Id.Invalid; }, @@ -1169,12 +1187,15 @@ test "tokenizer" { testTokenize("test", []Token.Id{Token.Id.Keyword_test}); } -test "tokenizer - unknown length pointer" { +test "tokenizer - unknown length pointer and then c pointer" { testTokenize( \\[*]u8 + \\[*c]u8 , []Token.Id{ Token.Id.BracketStarBracket, Token.Id.Identifier, + Token.Id.BracketStarCBracket, + Token.Id.Identifier, }); } From d9e01be97386f008e4a4b4281658f25b50ff80f1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 14:56:59 -0500 Subject: [PATCH 170/218] translate-c: use C pointer type everywhere See #1059 --- src/analyze.cpp | 9 +++++++ src/analyze.hpp | 1 + src/ast_render.cpp | 27 +++++++++---------- src/ast_render.hpp | 3 --- src/translate_c.cpp | 50 ++++++++++++----------------------- test/translate_c.zig | 62 ++++++++++++++++++++++---------------------- 6 files changed, 72 insertions(+), 80 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index e561050e0d..691579200e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6872,3 +6872,12 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no return ErrorNone; } + +const char *container_string(ContainerKind kind) { + switch (kind) { + case ContainerKindEnum: return "enum"; + case ContainerKindStruct: return "struct"; + case ContainerKindUnion: return "union"; + } + zig_unreachable(); +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 9773782510..1e4f2f2ce7 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -215,6 +215,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); bool type_is_c_abi_int(CodeGen *g, ZigType *ty); bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); +const char *container_string(ContainerKind kind); uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 34a7faa2a5..7b57841205 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) { return (tok == nullptr) ? "" : "threadlocal "; } -const char *container_string(ContainerKind kind) { - switch (kind) { - case ContainerKindEnum: return "enum"; - case ContainerKindStruct: return "struct"; - case ContainerKindUnion: return "union"; +static const char *token_to_ptr_len_str(Token *tok) { + assert(tok != nullptr); + switch (tok->id) { + case TokenIdStar: + case TokenIdStarStar: + return "*"; + case TokenIdBracketStarBracket: + return "[*]"; + case TokenIdBracketStarCBracket: + return "[*c]"; + default: + zig_unreachable(); } - zig_unreachable(); } static const char *node_type_str(NodeType node_type) { @@ -644,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypePointerType: { if (!grouped) fprintf(ar->f, "("); - const char *star = "[*]"; - if (node->data.pointer_type.star_token != nullptr && - (node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar)) - { - star = "*"; - } - fprintf(ar->f, "%s", star); + const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token); + fprintf(ar->f, "%s", ptr_len_str); if (node->data.pointer_type.align_expr != nullptr) { fprintf(ar->f, "align("); render_node_grouped(ar, node->data.pointer_type.align_expr); diff --git a/src/ast_render.hpp b/src/ast_render.hpp index d37002d8c7..1652156eee 100644 --- a/src/ast_render.hpp +++ b/src/ast_render.hpp @@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent); void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size); -const char *container_string(ContainerKind kind); - #endif - diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 02fa3b24be..b06a28d12d 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -291,11 +291,22 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod node); } +static TokenId ptr_len_to_token_id(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return TokenIdStar; + case PtrLenUnknown: + return TokenIdBracketStarBracket; + case PtrLenC: + return TokenIdBracketStarCBracket; + } + zig_unreachable(); +} + static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) { AstNode *node = trans_create_node(c, NodeTypePointerType); node->data.pointer_type.star_token = allocate(1); - node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket; - node->data.pointer_type.is_const = is_const; + node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len); node->data.pointer_type.is_const = is_const; node->data.pointer_type.is_volatile = is_volatile; node->data.pointer_type.op_expr = child_node; @@ -752,30 +763,6 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { } } -static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { - switch (ty->getTypeClass()) { - case Type::Builtin: { - const BuiltinType *builtin_ty = static_cast(ty); - return builtin_ty->getKind() == BuiltinType::Void; - } - case Type::Record: { - const RecordType *record_ty = static_cast(ty); - return record_ty->getDecl()->getDefinition() == nullptr; - } - case Type::Elaborated: { - const ElaboratedType *elaborated_ty = static_cast(ty); - return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); - } - case Type::Typedef: { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); - return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); - } - default: - return false; - } -} - static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { switch (ty->getTypeClass()) { case Type::Builtin: @@ -925,11 +912,8 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown; - - AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, ptr_len); - return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); + return trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenC); } case Type::Typedef: { @@ -1113,7 +1097,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return nullptr; } AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown); + child_qt.isVolatileQualified(), child_type_node, PtrLenC); return pointer_node; } case Type::BlockPointer: @@ -4568,7 +4552,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t } else if (first_tok->id == CTokIdAsterisk) { *tok_i += 1; - node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown); + node = trans_create_node_ptr_type(c, false, false, node, PtrLenC); } else { return node; } diff --git a/test/translate_c.zig b/test/translate_c.zig index 13f2a964d0..746fa60b18 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -117,11 +117,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; , \\pub const struct_Foo = extern struct { - \\ a: ?[*]Foo, + \\ a: [*c]Foo, \\}; \\pub const Foo = struct_Foo; \\pub const struct_Bar = extern struct { - \\ a: ?[*]Foo, + \\ a: [*c]Foo, \\}; ); @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , - \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; + \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void; ); cases.add("simple struct", @@ -213,7 +213,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\const struct_Foo = extern struct { \\ x: c_int, - \\ y: ?[*]u8, + \\ y: [*c]u8, \\}; , \\pub const Foo = struct_Foo; @@ -244,7 +244,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const BarB = enum_Bar.B; , - \\pub extern fn func(a: ?[*]struct_Foo, b: ?[*](?[*]enum_Bar)) void; + \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void; , \\pub const Foo = struct_Foo; , @@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("constant size array", \\void func(int array[20]); , - \\pub extern fn func(array: ?[*]c_int) void; + \\pub extern fn func(array: [*c]c_int) void; ); cases.add("self referential struct with function pointer", @@ -263,7 +263,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; , \\pub const struct_Foo = extern struct { - \\ derp: ?extern fn(?[*]struct_Foo) void, + \\ derp: ?extern fn([*c]struct_Foo) void, \\}; , \\pub const Foo = struct_Foo; @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const struct_Foo = @OpaqueType(); , - \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; + \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo; , \\pub const Foo = struct_Foo; ); @@ -322,11 +322,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; , \\pub const struct_Bar = extern struct { - \\ next: ?[*]struct_Foo, + \\ next: [*c]struct_Foo, \\}; , \\pub const struct_Foo = extern struct { - \\ next: ?[*]struct_Bar, + \\ next: [*c]struct_Bar, \\}; ); @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const Foo = c_void; , - \\pub extern fn fun(a: ?*Foo) Foo; + \\pub extern fn fun(a: [*c]Foo) Foo; ); cases.add("generate inline func for #define global extern fn", @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 6; \\} , - \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { + \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; \\ if ((b != 0) and (c != null)) return 1; \\ if ((a != 0) and (c != null)) return 2; @@ -710,7 +710,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const struct_Foo = extern struct { \\ field: c_int, \\}; - \\pub export fn read_field(foo: ?[*]struct_Foo) c_int { + \\pub export fn read_field(foo: [*c]struct_Foo) c_int { \\ return foo.?.field; \\} ); @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return x; \\} , - \\pub export fn foo(x: ?[*]c_ushort) ?*c_void { - \\ return @ptrCast(?*c_void, x); + \\pub export fn foo(x: [*c]c_ushort) [*c]c_void { + \\ return @ptrCast([*c]c_void, x); \\} ); @@ -777,7 +777,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 0; \\} , - \\pub export fn foo() ?[*]c_int { + \\pub export fn foo() [*c]c_int { \\ return null; \\} ); @@ -1086,7 +1086,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ *x = 1; \\} , - \\pub export fn foo(x: ?[*]c_int) void { + \\pub export fn foo(x: [*c]c_int) void { \\ x.?.* = 1; \\} ); @@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub fn foo() c_int { \\ var x: c_int = 1234; - \\ var ptr: ?[*]c_int = &x; + \\ var ptr: [*c]c_int = &x; \\ return ptr.?.*; \\} ); @@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return "bar"; \\} , - \\pub fn foo() ?[*]const u8 { + \\pub fn foo() [*c]const u8 { \\ return c"bar"; \\} ); @@ -1253,8 +1253,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return (float *)a; \\} , - \\fn ptrcast(a: ?[*]c_int) ?[*]f32 { - \\ return @ptrCast(?[*]f32, a); + \\fn ptrcast(a: [*c]c_int) [*c]f32 { + \\ return @ptrCast([*c]f32, a); \\} ); @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !c; \\} , - \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { + \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); @@ -1297,7 +1297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("const ptr initializer", \\static const char *v0 = "0.0.0"; , - \\pub var v0: ?[*]const u8 = c"0.0.0"; + \\pub var v0: [*c]const u8 = c"0.0.0"; ); cases.add("static incomplete array inside function", @@ -1306,17 +1306,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub fn foo() void { - \\ const v2: [*]const u8 = c"2.2.2"; + \\ const v2: [*c]const u8 = c"2.2.2"; \\} ); cases.add("macro pointer cast", \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) , - \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*]NRF_GPIO_Type)(NRF_GPIO_BASE); + \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*c]NRF_GPIO_Type)(NRF_GPIO_BASE); ); - cases.add("if on none bool", + cases.add("if on non-bool", \\enum SomeEnum { A, B, C }; \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { \\ if (a) return 0; @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ B, \\ C, \\}; - \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { + \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; \\ if (c != null) return 2; @@ -1343,7 +1343,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); - cases.add("while on none bool", + cases.add("while on non-bool", \\int while_none_bool(int a, float b, void *c) { \\ while (a) return 0; \\ while (b) return 1; @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { + \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != null) return 2; @@ -1359,7 +1359,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); - cases.add("for on none bool", + cases.add("for on non-bool", \\int for_none_bool(int a, float b, void *c) { \\ for (;a;) return 0; \\ for (;b;) return 1; @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { + \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != null) return 2; From 342bca7f4627454435e9f6c2d12b099f95a2fd47 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 15:31:09 -0500 Subject: [PATCH 171/218] C pointer comparison and arithmetic See #1059 --- src/analyze.cpp | 2 +- src/codegen.cpp | 4 +-- src/ir.cpp | 46 +++++++++++++++++++++++++++---- src/translate_c.cpp | 8 ++++-- test/stage1/behavior/pointers.zig | 20 ++++++++++++++ test/translate_c.zig | 18 ++++++------ 6 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 691579200e..af6200cc82 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint32_t bit_offset_in_host, uint32_t host_int_bytes) { assert(!type_is_invalid(child_type)); - assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); + assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); if (byte_alignment != 0) { uint32_t abi_alignment = get_abi_alignment(g, child_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4868576b49..605ea59b06 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) || (op1->value.type->id == ZigTypeIdPointer && (op_id == IrBinOpAdd || op_id == IrBinOpSub) && - op1->value.type->data.pointer.ptr_len == PtrLenUnknown) + op1->value.type->data.pointer.ptr_len != PtrLenSingle) ); ZigType *operand_type = op1->value.type; ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; @@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, AddSubMulMul; if (scalar_type->id == ZigTypeIdPointer) { - assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); + assert(scalar_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef subscript_value; if (operand_type->id == ZigTypeIdVector) zig_panic("TODO: Implement vector operations on pointers."); diff --git a/src/ir.cpp b/src/ir.cpp index 30350d75de..bc37ac9b54 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t * *errors = reallocate(*errors, old_errors_count, *errors_count); } -static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) { +static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, + IrInstruction **instructions, size_t instruction_count) +{ Error err; assert(instruction_count >= 1); IrInstruction *prev_inst = instructions[0]; @@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT continue; } + if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC && + (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt)) + { + continue; + } + + if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC && + (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt)) + { + prev_inst = cur_inst; + continue; + } + if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { continue; } @@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdBool: case ZigTypeIdMetaType: case ZigTypeIdVoid: - case ZigTypeIdPointer: case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdOpaque: @@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * operator_allowed = is_equality_cmp; break; + case ZigTypeIdPointer: + operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); + break; + case ZigTypeIdUnreachable: case ZigTypeIdArray: case ZigTypeIdStruct: @@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) { zig_unreachable(); } +static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { + if (lhs_type->id != ZigTypeIdPointer) + return false; + switch (op) { + case IrBinOpAdd: + case IrBinOpSub: + break; + default: + return false; + } + switch (lhs_type->data.pointer.ptr_len) { + case PtrLenSingle: + return false; + case PtrLenUnknown: + case PtrLenC: + break; + } + return true; +} + static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) @@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp IrBinOp op_id = instruction->op_id; // look for pointer math - if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && - (op_id == IrBinOpAdd || op_id == IrBinOpSub)) - { + if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index b06a28d12d..63f04dae6c 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im return node; } case CK_NullToPointer: - return trans_create_node(c, NodeTypeNullLiteral); + return trans_create_node_unsigned(c, 0); case CK_Dependent: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); return nullptr; @@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * case BuiltinType::Float16: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); case BuiltinType::NullPtr: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); + return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, + trans_create_node_unsigned(c, 0)); case BuiltinType::Void: case BuiltinType::Half: @@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * break; } case Type::Pointer: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); + return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, + trans_create_node_unsigned(c, 0)); case Type::Typedef: { diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 79832bc316..63e4c314b1 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" { z.* += 1; expect(y == 12); } + +test "C pointer comparison and arithmetic" { + var one: usize = 1; + var ptr1: [*c]u8 = 0; + var ptr2 = ptr1 + 10; + expect(ptr1 == 0); + expect(ptr1 >= 0); + expect(ptr1 <= 0); + expect(ptr1 < 1); + expect(ptr1 < one); + expect(1 > ptr1); + expect(one > ptr1); + expect(ptr1 < ptr2); + expect(ptr2 > ptr1); + expect(ptr2 >= 10); + expect(ptr2 == 10); + expect(ptr2 <= 10); + ptr2 -= 10; + expect(ptr1 == ptr2); +} diff --git a/test/translate_c.zig b/test/translate_c.zig index 746fa60b18..b87b962edc 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; - \\ if ((b != 0) and (c != null)) return 1; - \\ if ((a != 0) and (c != null)) return 2; + \\ if ((b != 0) and (c != 0)) return 1; + \\ if ((a != 0) and (c != 0)) return 2; \\ if ((a != 0) or (b != 0)) return 3; - \\ if ((b != 0) or (c != null)) return 4; - \\ if ((a != 0) or (c != null)) return 5; + \\ if ((b != 0) or (c != 0)) return 4; + \\ if ((a != 0) or (c != 0)) return 5; \\ return 6; \\} ); @@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub export fn foo() [*c]c_int { - \\ return null; + \\ return 0; \\} ); @@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); - \\ return !(c != null); + \\ return !(c != 0); \\} ); @@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; - \\ if (c != null) return 2; + \\ if (c != 0) return 2; \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3; \\ return 4; \\} @@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != null) return 2; + \\ while (c != 0) return 2; \\ return 3; \\} ); @@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != null) return 2; + \\ while (c != 0) return 2; \\ return 3; \\} ); From 90b8cd4a45bcb2ca131b6ed6466f799aaa162d13 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 16:07:40 -0500 Subject: [PATCH 172/218] add C pointer type to @typeInfo See #1059 --- src-self-hosted/type.zig | 2 ++ src/codegen.cpp | 1 + src/ir.cpp | 14 +++++++++++++- std/fmt/index.zig | 3 +++ std/meta/index.zig | 9 ++++++--- std/testing.zig | 3 +-- test/stage1/behavior/type_info.zig | 15 +++++++++++++++ 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 8a05594b30..790b51b7be 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -794,6 +794,7 @@ pub const Type = struct { Size.One => "*", Size.Many => "[*]", Size.Slice => "[]", + Size.C => "[*c]", }; const mut_str = switch (self.key.mut) { Mut.Const => "const ", @@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 { builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed), builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"), builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"), + builtin.TypeInfo.Pointer.Size.C => unreachable, } }, builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed), diff --git a/src/codegen.cpp b/src/codegen.cpp index 605ea59b06..142e8174f5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7309,6 +7309,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " One,\n" " Many,\n" " Slice,\n" + " C,\n" " };\n" " };\n" "\n" diff --git a/src/ir.cpp b/src/ir.cpp index bc37ac9b54..36ea50ed52 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17584,6 +17584,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco return ErrorNone; } +static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return 0; + case PtrLenUnknown: + return 1; + case PtrLenC: + return 3; + } + zig_unreachable(); +} + static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { Error err; ZigType *attrs_type; @@ -17593,7 +17605,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty size_enum_index = 2; } else if (ptr_type_entry->id == ZigTypeIdPointer) { attrs_type = ptr_type_entry; - size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1; + size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); } else { zig_unreachable(); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 05b028112f..b09fe21032 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -236,6 +236,9 @@ pub fn formatType( 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) { diff --git a/std/meta/index.zig b/std/meta/index.zig index 3f8ea762a6..652e2d39ec 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Pointer => { const info = @typeInfo(T).Pointer; switch (info.size) { - builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b, + 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; + if (a == null and b == null) return true; + if (a == null or b == null) return false; return eql(a.?, b.?); }, else => return a == b, diff --git a/std/testing.zig b/std/testing.zig index ade6e8b0dd..f3ce69659d 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -69,7 +69,7 @@ pub fn expectEqual(expected: var, actual: var) void { } }, - builtin.TypeInfo.Pointer.Size.Slice => { + builtin.TypeInfo.Pointer.Size.Slice => { if (actual.ptr != expected.ptr) { std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr); } @@ -122,7 +122,6 @@ pub fn expectEqual(expected: var, actual: var) void { } } }, - } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index ce0ad795b4..dc185cc960 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -61,6 +61,21 @@ fn testUnknownLenPtr() void { expect(u32_ptr_info.Pointer.child == f64); } +test "type info: C pointer type info" { + testCPtr(); + comptime testCPtr(); +} + +fn testCPtr() void { + const ptr_info = @typeInfo([*c]align(4) const i8); + expect(TypeId(ptr_info) == TypeId.Pointer); + expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); + expect(ptr_info.Pointer.is_const); + expect(!ptr_info.Pointer.is_volatile); + expect(ptr_info.Pointer.alignment == 4); + expect(ptr_info.Pointer.child == i8); +} + test "type info: slice type info" { testSlice(); comptime testSlice(); From 57a7ab0d330416f15c0288004b67101c1c3e9629 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 19:12:01 -0500 Subject: [PATCH 173/218] comptime support for pointer arithmetic with hard coded addresses --- src/ir.cpp | 109 +++++++++++++++++++++++------- test/stage1/behavior/pointers.zig | 40 ++++++----- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 36ea50ed52..5ec397b0b2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11682,28 +11682,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp } static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { - if (op_id == IrBinOpCmpEq) { - return cmp == CmpEQ; - } else if (op_id == IrBinOpCmpNotEq) { - return cmp != CmpEQ; - } else if (op_id == IrBinOpCmpLessThan) { - return cmp == CmpLT; - } else if (op_id == IrBinOpCmpGreaterThan) { - return cmp == CmpGT; - } else if (op_id == IrBinOpCmpLessOrEq) { - return cmp != CmpGT; - } else if (op_id == IrBinOpCmpGreaterOrEq) { - return cmp != CmpLT; - } else { - zig_unreachable(); + switch (op_id) { + case IrBinOpCmpEq: + return cmp == CmpEQ; + case IrBinOpCmpNotEq: + return cmp != CmpEQ; + case IrBinOpCmpLessThan: + return cmp == CmpLT; + case IrBinOpCmpGreaterThan: + return cmp == CmpGT; + case IrBinOpCmpLessOrEq: + return cmp != CmpGT; + case IrBinOpCmpGreaterOrEq: + return cmp != CmpLT; + default: + zig_unreachable(); } } static bool optional_value_is_null(ConstExprValue *val) { assert(val->special == ConstValSpecialStatic); if (get_codegen_ptr_type(val->type) != nullptr) { - return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr == 0; + if (val->data.x_ptr.special == ConstPtrSpecialNull) { + return true; + } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { + return val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else { + return false; + } } else if (is_opt_err_set(val->type)) { return val->data.x_err_set == nullptr; } else { @@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * break; case ZigTypeIdPointer: - operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); + operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC); break; case ZigTypeIdUnreachable: @@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * if (op2_val == nullptr) return ira->codegen->invalid_instruction; - bool answer; if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { Cmp cmp_result = float_cmp(op1_val, op2_val); - answer = resolve_cmp_op_id(op_id, cmp_result); + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) { Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); - answer = resolve_cmp_op_id(op_id, cmp_result); + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); + } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { + if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op1_val->data.x_ptr.special == ConstPtrSpecialNull) && + (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op2_val->data.x_ptr.special == ConstPtrSpecialNull)) + { + uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? + 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; + uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? + 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; + Cmp cmp_result; + if (op1_addr > op2_addr) { + cmp_result = CmpGT; + } else if (op1_addr < op2_addr) { + cmp_result = CmpLT; + } else { + cmp_result = CmpEQ; + } + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); + } } else { bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); + bool answer; if (op_id == IrBinOpCmpEq) { answer = are_equal; } else if (op_id == IrBinOpCmpNotEq) { @@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * } else { zig_unreachable(); } + return ir_const_bool(ira, &bin_op_instruction->base, answer); } - - return ir_const_bool(ira, &bin_op_instruction->base, answer); } // some comparisons with unsigned numbers can be evaluated @@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { } static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { + Error err; + IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp // look for pointer math if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); - if (casted_op2 == ira->codegen->invalid_instruction) + if (type_is_invalid(casted_op2->value.type)) return ira->codegen->invalid_instruction; + if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { + IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); + result->value.special = ConstValSpecialUndef; + return result; + } + if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic && + (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op1->value.data.x_ptr.special == ConstPtrSpecialNull)) + { + uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? + 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; + uint64_t elem_offset; + if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) + return ira->codegen->invalid_instruction; + ZigType *elem_type = op1->value.type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_instruction; + uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; + uint64_t new_addr; + if (op_id == IrBinOpAdd) { + new_addr = start_addr + byte_offset; + } else if (op_id == IrBinOpSub) { + new_addr = start_addr - byte_offset; + } else { + zig_unreachable(); + } + IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); + result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; + result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; + return result; + } + IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, instruction->base.source_node, op_id, op1, casted_op2, true); result->value.type = op1->value.type; diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 63e4c314b1..4375a6971f 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -58,21 +58,27 @@ test "implicit cast single item pointer to C pointer and back" { } test "C pointer comparison and arithmetic" { - var one: usize = 1; - var ptr1: [*c]u8 = 0; - var ptr2 = ptr1 + 10; - expect(ptr1 == 0); - expect(ptr1 >= 0); - expect(ptr1 <= 0); - expect(ptr1 < 1); - expect(ptr1 < one); - expect(1 > ptr1); - expect(one > ptr1); - expect(ptr1 < ptr2); - expect(ptr2 > ptr1); - expect(ptr2 >= 10); - expect(ptr2 == 10); - expect(ptr2 <= 10); - ptr2 -= 10; - expect(ptr1 == ptr2); + const S = struct { + fn doTheTest() void { + var one: usize = 1; + var ptr1: [*c]u32 = 0; + var ptr2 = ptr1 + 10; + expect(ptr1 == 0); + expect(ptr1 >= 0); + expect(ptr1 <= 0); + expect(ptr1 < 1); + expect(ptr1 < one); + expect(1 > ptr1); + expect(one > ptr1); + expect(ptr1 < ptr2); + expect(ptr2 > ptr1); + expect(ptr2 >= 40); + expect(ptr2 == 40); + expect(ptr2 <= 40); + ptr2 -= 10; + expect(ptr1 == ptr2); + } + }; + S.doTheTest(); + comptime S.doTheTest(); } From 069fc1a26990b3946cf788b4ebe5edefca5a3bfd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 19:21:59 -0500 Subject: [PATCH 174/218] peer type resolution with C pointers See #1059 --- src/ir.cpp | 18 ++++++++++++++++++ test/stage1/behavior/pointers.zig | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index 5ec397b0b2..91c8503234 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9275,6 +9275,24 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT continue; } + if (prev_type->id == ZigTypeIdPointer && cur_type->id == ZigTypeIdPointer) { + if (prev_type->data.pointer.ptr_len == PtrLenC && + types_match_const_cast_only(ira, prev_type->data.pointer.child_type, + cur_type->data.pointer.child_type, source_node, + !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + continue; + } + if (cur_type->data.pointer.ptr_len == PtrLenC && + types_match_const_cast_only(ira, cur_type->data.pointer.child_type, + prev_type->data.pointer.child_type, source_node, + !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + prev_inst = cur_inst; + continue; + } + } + if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { continue; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 4375a6971f..3f62bd1cec 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -82,3 +82,18 @@ test "C pointer comparison and arithmetic" { S.doTheTest(); comptime S.doTheTest(); } + +test "peer type resolution with C pointers" { + var ptr_one: *u8 = undefined; + var ptr_many: [*]u8 = undefined; + var ptr_c: [*c]u8 = undefined; + var t = true; + var x1 = if (t) ptr_one else ptr_c; + var x2 = if (t) ptr_many else ptr_c; + var x3 = if (t) ptr_c else ptr_one; + var x4 = if (t) ptr_c else ptr_many; + expect(@typeOf(x1) == [*c]u8); + expect(@typeOf(x2) == [*c]u8); + expect(@typeOf(x3) == [*c]u8); + expect(@typeOf(x4) == [*c]u8); +} From 0abe6d668eb52aefa59c75a8d8f782f2372f8600 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 00:39:08 -0500 Subject: [PATCH 175/218] C pointers: delete dead code in ir_num_lit_fits_in_other_type --- src/ir.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 91c8503234..1f0edc910d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8555,20 +8555,6 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } } } - if (other_type->id == ZigTypeIdPointer && other_type->data.pointer.ptr_len == PtrLenC && const_val_is_int) { - if (!bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, true) && - !bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, false)) - { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - - ir_add_error(ira, instruction, - buf_sprintf("integer value %s outside of pointer address range", - buf_ptr(val_buf))); - return false; - } - return true; - } const char *num_lit_str; Buf *val_buf = buf_alloc(); From 285e2f62ba0648d6d8e7ff64d1ee7d2900481e2f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 00:51:06 -0500 Subject: [PATCH 176/218] disallow C pointers to non-C-ABI-compatible element types See #1059 --- src/analyze.cpp | 2 +- src/analyze.hpp | 2 +- src/ir.cpp | 4 ++++ test/compile_errors.zig | 10 ++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index af6200cc82..ab2afba561 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1469,7 +1469,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { zig_unreachable(); } -static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { +bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); diff --git a/src/analyze.hpp b/src/analyze.hpp index 1e4f2f2ce7..c8141b02ff 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -44,7 +44,7 @@ void find_libc_include_path(CodeGen *g); void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); - +bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/ir.cpp b/src/ir.cpp index 1f0edc910d..64e08ef7ea 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21145,6 +21145,10 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); return ira->codegen->invalid_instruction; + } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; } uint32_t align_bytes; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index b47cdf2ed1..63850bb888 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "C pointer pointing to non C ABI compatible type", + \\const Foo = struct {}; + \\export fn entry() [*c]Foo { + \\ return undefined; + \\} + , + ".tmp_source.zig:2:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ); + cases.addTest( "@truncate undefined value", \\export fn entry() void { From 6f05e8d1be083a429673e717e8b3c736c7ddb8d2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 01:38:11 -0500 Subject: [PATCH 177/218] implicit casting between C pointer and optional non-C pointer See #1059 --- src/ir.cpp | 34 +++++++++++++++++++------------ test/stage1/behavior/pointers.zig | 10 +++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 64e08ef7ea..00d82c9224 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8669,33 +8669,41 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } // pointer const - if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const); + ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); + ZigType *actual_ptr_type = get_src_ptr_type(actual_type); + bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; + bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; + if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) || + (wanted_ptr_type != nullptr && actual_is_c_ptr) || + (actual_ptr_type != nullptr && wanted_is_c_ptr)) + { + ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, + actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdPointerChild; result.data.pointer_mismatch = allocate_nonzero(1); result.data.pointer_mismatch->child = child; - result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type; - result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type; + result.data.pointer_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; + result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; return result; } - if ((err = type_resolve(g, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; } - if ((err = type_resolve(g, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; } - if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) && - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) && - actual_type->data.pointer.bit_offset_in_host == wanted_type->data.pointer.bit_offset_in_host && - actual_type->data.pointer.host_int_bytes == wanted_type->data.pointer.host_int_bytes && - get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type)) + bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; + if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && + (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && + (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && + actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && + actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && + get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type)) { return result; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 3f62bd1cec..8d87fe2a20 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -97,3 +97,13 @@ test "peer type resolution with C pointers" { expect(@typeOf(x3) == [*c]u8); expect(@typeOf(x4) == [*c]u8); } + +test "implicit casting between C pointer and optional non-C pointer" { + var slice: []const u8 = "aoeu"; + const opt_many_ptr: ?[*]const u8 = slice.ptr; + var ptr_opt_many_ptr = &opt_many_ptr; + var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + expect(c_ptr.*.* == 'a'); + ptr_opt_many_ptr = c_ptr; + expect(ptr_opt_many_ptr.*.?[1] == 'o'); +} From 270933b1e997c91a9c2d28b6896d625c0ae1b163 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 10:25:21 -0500 Subject: [PATCH 178/218] compile error test for casting integer to c pointer when the int has more bits than pointers See #1059 --- src/ir.cpp | 4 +++- test/compile_errors.zig | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 00d82c9224..50b5661e12 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10882,7 +10882,9 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou ira->codegen->builtin_types.entry_usize->data.integral.bit_count) { ir_add_error(ira, source_instr, - buf_sprintf("integer type too big for implicit @intToPtr to type '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("integer type '%s' too big for implicit @intToPtr to type '%s'", + buf_ptr(&integer->value.type->name), + buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 63850bb888..8f8e2a0bdf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,20 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting too big integers to C pointers", + \\export fn a() void { + \\ var ptr: [*c]u8 = (1 << 64) + 1; + \\} + \\export fn b() void { + \\ var x: @IntType(false, 65) = 0x1234; + \\ 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'", + ); + cases.addTest( "C pointer pointing to non C ABI compatible type", \\const Foo = struct {}; From 5699ab5e77f8d13cac1e34775e6e51358119965c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 18:20:00 -0500 Subject: [PATCH 179/218] C pointers: errors for nested pointer casting regarding null See #1059 --- src/all_types.hpp | 12 +++-- src/analyze.cpp | 45 +++++++++++----- src/ir.cpp | 99 ++++++++++++++++++++++++---------- test/compile_errors.zig | 114 ++++++++++++++++++++++++---------------- 4 files changed, 181 insertions(+), 89 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index fd66b77ad2..230dba9a42 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -691,15 +691,17 @@ struct AstNodePointerType { AstNode *align_expr; BigInt *bit_offset_start; BigInt *host_int_bytes; + AstNode *op_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; - AstNode *op_expr; }; struct AstNodeArrayType { AstNode *size; AstNode *child_type; AstNode *align_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; }; @@ -1050,6 +1052,7 @@ struct ZigTypePointer { uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned bool is_const; bool is_volatile; + bool allow_zero; }; struct ZigTypeInt { @@ -1499,11 +1502,12 @@ struct TypeId { struct { ZigType *child_type; PtrLen ptr_len; - bool is_const; - bool is_volatile; uint32_t alignment; uint32_t bit_offset_in_host; uint32_t host_int_bytes; + bool is_const; + bool is_volatile; + bool allow_zero; } pointer; struct { ZigType *child_type; @@ -2592,6 +2596,7 @@ struct IrInstructionPtrType { PtrLen ptr_len; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionPromiseType { @@ -2607,6 +2612,7 @@ struct IrInstructionSliceType { IrInstruction *child_type; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionAsm { diff --git a/src/analyze.cpp b/src/analyze.cpp index ab2afba561..900def52d4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -433,6 +433,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) { + // TODO when implementing https://github.com/ziglang/zig/issues/1953 + // move this to a parameter + bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); @@ -452,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons TypeId type_id = {}; ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { + if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; @@ -461,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; type_id.data.pointer.host_int_bytes = host_int_bytes; type_id.data.pointer.ptr_len = ptr_len; + type_id.data.pointer.allow_zero = allow_zero; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -481,18 +485,28 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; + const char *allow_zero_str; + if (ptr_len == PtrLenC) { + assert(allow_zero); + allow_zero_str = ""; + } else { + allow_zero_str = allow_zero ? "allowzero " : ""; + } buf_resize(&entry->name, 0); if (host_int_bytes == 0 && byte_alignment == 0) { - buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%s%s%s%s%s", + star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (host_int_bytes == 0) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, - const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (byte_alignment == 0) { - buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } else { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } assert(child_type->id != ZigTypeIdInvalid); @@ -500,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->zero_bits = !type_has_bits(child_type); if (!entry->zero_bits) { - if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) { + if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || + bit_offset_in_host != 0 || allow_zero) + { ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenSingle, 0, 0, host_int_bytes); entry->type_ref = peer_type->type_ref; @@ -534,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.bit_offset_in_host = bit_offset_in_host; entry->data.pointer.host_int_bytes = host_int_bytes; + entry->data.pointer.allow_zero = allow_zero; if (parent_pointer) { *parent_pointer = entry; @@ -850,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_type = ptr_type->data.pointer.child_type; if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0) + ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenUnknown, 0, 0, 0); @@ -873,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0) + child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero) { ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, @@ -4053,7 +4070,9 @@ ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdPromise) return type; if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type; + if (type->data.maybe.child_type->id == ZigTypeIdPointer) { + return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; + } if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type; } @@ -6289,6 +6308,7 @@ uint32_t type_id_hash(TypeId x) { ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + + (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); @@ -6339,6 +6359,7 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.ptr_len == b.data.pointer.ptr_len && a.data.pointer.is_const == b.data.pointer.is_const && a.data.pointer.is_volatile == b.data.pointer.is_volatile && + a.data.pointer.allow_zero == b.data.pointer.allow_zero && a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; diff --git a/src/ir.cpp b/src/ir.cpp index 50b5661e12..19bec193d5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -61,7 +61,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdNullWrapPtr + ConstCastResultIdBadAllowsZero, }; struct ConstCastOnly; @@ -83,6 +83,7 @@ struct ConstCastErrUnionErrSetMismatch; struct ConstCastErrUnionPayloadMismatch; struct ConstCastErrSetMismatch; struct ConstCastTypeMismatch; +struct ConstCastBadAllowsZero; struct ConstCastOnly { ConstCastResultId id; @@ -99,6 +100,7 @@ struct ConstCastOnly { ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; + ConstCastBadAllowsZero *bad_allows_zero; } data; }; @@ -141,6 +143,12 @@ struct ConstCastErrSetMismatch { ZigList missing_errors; }; +struct ConstCastBadAllowsZero { + ZigType *wanted_type; + ZigType *actual_type; +}; + + enum UndefAllowed { UndefOk, UndefBad, @@ -8636,6 +8644,14 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } +static bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) @@ -8649,34 +8665,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type == actual_type) return result; - // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively - // but not if we want a mutable pointer - // and not if the actual pointer has zero bits - if (!wanted_is_mutable && wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && - actual_type->id == ZigTypeIdPointer && type_has_bits(actual_type)) - { - ConstCastOnly child = types_match_const_cast_only(ira, - wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdNullWrapPtr; - result.data.null_wrap_ptr_child = allocate_nonzero(1); - *result.data.null_wrap_ptr_child = child; - } - return result; - } - - // pointer const + // If pointers have the same representation in memory, they can be "const-casted". + // `const` attribute can be gained + // `volatile` attribute can be gained + // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) + // but only if !wanted_is_mutable + // alignment can be decreased + // bit offset attributes must match exactly + // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); ZigType *actual_ptr_type = get_src_ptr_type(actual_type); + bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(actual_type); bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; - if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) || - (wanted_ptr_type != nullptr && actual_is_c_ptr) || - (actual_ptr_type != nullptr && wanted_is_c_ptr)) - { + bool wanted_opt_or_ptr = wanted_ptr_type != nullptr && + (wanted_type->id == ZigTypeIdPointer || wanted_type->id == ZigTypeIdOptional); + bool actual_opt_or_ptr = actual_ptr_type != nullptr && + (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); + if (wanted_opt_or_ptr && actual_opt_or_ptr) { + bool ok_allows_zero = (wanted_allows_zero && + (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (!wanted_allows_zero && !actual_allows_zero); + if (!ok_allows_zero) { + result.id = ConstCastResultIdBadAllowsZero; + result.data.bad_allows_zero = allocate_nonzero(1); + result.data.bad_allows_zero->wanted_type = wanted_type; + result.data.bad_allows_zero->actual_type = actual_type; + return result; + } ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -8699,6 +8716,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && + type_has_bits(wanted_type) == type_has_bits(actual_type) && (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && @@ -9922,7 +9940,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un if (undef_allowed == UndefOk) { return &value->value; } else { - ir_add_error(ira, value, buf_sprintf("use of undefined value")); + ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior")); return nullptr; } } @@ -10828,6 +10846,26 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); break; } + case ConstCastResultIdBadAllowsZero: { + bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type); + ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type; + ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type; + if (actual_allows_zero && !wanted_allows_zero) { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("'%s' could have null values which are illegal in type '%s'", + buf_ptr(&actual_elem_type->name), + buf_ptr(&wanted_elem_type->name))); + } else { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", + buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name), + buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name))); + } + break; + } case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO @@ -10838,7 +10876,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa case ConstCastResultIdFnArgNoAlias: // TODO case ConstCastResultIdUnresolvedInferredErrSet: // TODO case ConstCastResultIdAsyncAllocatorType: // TODO - case ConstCastResultIdNullWrapPtr: // TODO break; } } @@ -20589,12 +20626,14 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. - if (get_src_ptr_type(src_type) == nullptr) { + ZigType *src_ptr_type = get_src_ptr_type(src_type); + if (src_ptr_type == nullptr) { ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } - if (get_src_ptr_type(dest_type) == nullptr) { + ZigType *dest_ptr_type = get_src_ptr_type(dest_type); + if (dest_ptr_type == nullptr) { ir_add_error(ira, dest_type_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; @@ -20606,6 +20645,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } if (instr_is_comptime(ptr)) { + // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern + // of the pointer as the new pointer type. ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); if (!val) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8f8e2a0bdf..c51a65cadf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,30 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting C pointers which would mess up null semantics", + \\export fn entry() void { + \\ var slice: []const u8 = "aoeu"; + \\ const opt_many_ptr: [*]const u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + \\ ptr_opt_many_ptr = c_ptr; + \\} + \\export fn entry2() void { + \\ var buf: [4]u8 = "aoeu"; + \\ var slice: []u8 = &buf; + \\ var opt_many_ptr: [*]u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]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: '[*c]const u8' could have null values which are illegal in type '[*]const u8'", + ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'", + ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", + ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]u8'", + ); + cases.addTest( "implicit casting too big integers to C pointers", \\export fn a() void { @@ -31,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var z = @truncate(u8, u16(undefined)); \\} , - ".tmp_source.zig:2:30: error: use of undefined value", + ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior", ); cases.addTest( @@ -392,7 +416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ f(i32); \\} , - ".tmp_source.zig:4:5: error: use of undefined value", + ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -792,7 +816,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -805,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2776,7 +2800,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", + ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2786,7 +2810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a / a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2796,7 +2820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a /= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2806,7 +2830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a % a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2816,7 +2840,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a %= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2826,7 +2850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a + a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2836,7 +2860,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a += a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2846,7 +2870,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a +% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2856,7 +2880,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a +%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2866,7 +2890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a - a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2876,7 +2900,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2886,7 +2910,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a -% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2896,7 +2920,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2906,7 +2930,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a * a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2916,7 +2940,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2926,7 +2950,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a *% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2936,7 +2960,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2946,7 +2970,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a << 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2956,7 +2980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a <<= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2966,7 +2990,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >> 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2976,7 +3000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a >>= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2986,7 +3010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a & a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2996,7 +3020,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a &= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3006,7 +3030,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a | a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3016,7 +3040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a |= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3026,7 +3050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a ^ a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3036,7 +3060,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a ^= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3046,7 +3070,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a == a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3056,7 +3080,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a != a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3066,7 +3090,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a > a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3076,7 +3100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3086,7 +3110,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a < a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3096,7 +3120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a <= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3106,7 +3130,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a and a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3116,7 +3140,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a or a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3126,7 +3150,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3136,7 +3160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -%a; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3146,7 +3170,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = ~a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3156,7 +3180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = !a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3166,7 +3190,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a orelse false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3176,7 +3200,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a catch |err| false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( From 0b3db784f1cf21dd35fc14dfee29ab6fd867c0ed Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Sun, 3 Feb 2019 01:15:51 -0800 Subject: [PATCH 180/218] Enable compileLog to display slices --- src/analyze.cpp | 53 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 970d1cc382..b3b4c36cf1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6010,16 +6010,20 @@ static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const } } -static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) { - switch (const_val->data.x_array.special) { +static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ConstExprValue *const_val, uint64_t start, uint64_t len) { + ConstArrayValue *array = &const_val->data.x_array; + switch (array->special) { case ConstArraySpecialUndef: buf_append_str(buf, "undefined"); return; case ConstArraySpecialBuf: { - Buf *array_buf = const_val->data.x_array.data.s_buf; + Buf *array_buf = array->data.s_buf; + const char *base = &buf_ptr(array_buf)[start]; + assert(start + len <= buf_len(array_buf)); + buf_append_char(buf, '"'); - for (size_t i = 0; i < buf_len(array_buf); i += 1) { - uint8_t c = buf_ptr(array_buf)[i]; + for (size_t i = 0; i < len; i += 1) { + uint8_t c = base[i]; if (c == '"') { buf_append_str(buf, "\\\""); } else { @@ -6030,12 +6034,13 @@ static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_v return; } case ConstArraySpecialNone: { - buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name)); + ConstExprValue *base = &array->data.s_none.elements[start]; + assert(start + len <= const_val->type->data.array.len); + + buf_appendf(buf, "%s{", buf_ptr(type_name)); for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; - render_const_value(g, buf, child_value); + if (i != 0) buf_appendf(buf, ","); + render_const_value(g, buf, &base[i]); } buf_appendf(buf, "}"); return; @@ -6124,10 +6129,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdPointer: return render_const_val_ptr(g, buf, const_val, type_entry); - case ZigTypeIdVector: - return render_const_val_array(g, buf, const_val, type_entry->data.vector.len); - case ZigTypeIdArray: - return render_const_val_array(g, buf, const_val, type_entry->data.array.len); + case ZigTypeIdArray: { + uint64_t len = type_entry->data.array.len; + render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); + return; + } + case ZigTypeIdVector: { + uint32_t len = type_entry->data.vector.len; + render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); + return; + } case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -6169,7 +6180,19 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdStruct: { - buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); + if (is_slice(type_entry)) { + ConstPtrValue *ptr = &const_val->data.x_struct.fields[slice_ptr_index].data.x_ptr; + assert(ptr->special == ConstPtrSpecialBaseArray); + ConstExprValue *array = ptr->data.base_array.array_val; + size_t start = ptr->data.base_array.elem_index; + + ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; + size_t len = bigint_as_unsigned(&len_val->data.x_bigint); + + render_const_val_array(g, buf, &type_entry->name, array, start, len); + } else { + buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); + } return; } case ZigTypeIdEnum: From be861a85c8a1adc1f82c523136e6d6b18992c372 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Wed, 13 Feb 2019 23:24:52 +1300 Subject: [PATCH 181/218] compiler-rt: Add __addtf3, __subtf3 and __truncdfhf2 Allows addition/subtraction of f128 and narrowing casts to f16 from larger float types. --- CMakeLists.txt | 1 + std/special/compiler_rt/addXf3.zig | 191 ++++++++++++++++++++ std/special/compiler_rt/addXf3_test.zig | 85 +++++++++ std/special/compiler_rt/index.zig | 4 + std/special/compiler_rt/truncXfYf2.zig | 4 + std/special/compiler_rt/truncXfYf2_test.zig | 68 +++++++ 6 files changed, 353 insertions(+) create mode 100644 std/special/compiler_rt/addXf3.zig create mode 100644 std/special/compiler_rt/addXf3_test.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index ed79f99901..41fa44374e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -608,6 +608,7 @@ set(ZIG_STD_FILES "special/bootstrap_lib.zig" "special/build_runner.zig" "special/builtin.zig" + "special/compiler_rt/addXf3.zig" "special/compiler_rt/aulldiv.zig" "special/compiler_rt/aullrem.zig" "special/compiler_rt/comparetf2.zig" diff --git a/std/special/compiler_rt/addXf3.zig b/std/special/compiler_rt/addXf3.zig new file mode 100644 index 0000000000..5f7f73c44f --- /dev/null +++ b/std/special/compiler_rt/addXf3.zig @@ -0,0 +1,191 @@ +// Ported from: +// +// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/lib/builtins/fp_add_impl.inc + +const std = @import("std"); +const builtin = @import("builtin"); +const compiler_rt = @import("index.zig"); + +pub extern fn __addtf3(a: f128, b: f128) f128 { + return addXf3(f128, a, b); +} + +pub extern fn __subtf3(a: f128, b: f128) f128 { + const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (u128(1) << 127)); + return addXf3(f128, a, neg_b); +} + +inline fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 { + const Z = @IntType(false, T.bit_count); + const significandBits = std.math.floatMantissaBits(T); + const implicitBit = Z(1) << significandBits; + + const shift = @clz(significand.*) - @clz(implicitBit); + significand.* <<= @intCast(u7, shift); + return 1 - shift; +} + +inline fn addXf3(comptime T: type, a: T, b: T) T { + const Z = @IntType(false, T.bit_count); + + const typeWidth = T.bit_count; + const significandBits = std.math.floatMantissaBits(T); + const exponentBits = std.math.floatExponentBits(T); + + const signBit = (Z(1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const implicitBit = (Z(1) << significandBits); + const quietBit = implicitBit >> 1; + const significandMask = implicitBit - 1; + + const absMask = signBit - 1; + const exponentMask = absMask ^ significandMask; + const qnanRep = exponentMask | quietBit; + + var aRep = @bitCast(Z, a); + var bRep = @bitCast(Z, b); + const aAbs = aRep & absMask; + const bAbs = bRep & absMask; + + const negative = (aRep & signBit) != 0; + const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias; + const significand = (aAbs & significandMask) | implicitBit; + + const infRep = @bitCast(Z, std.math.inf(T)); + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - Z(1) >= infRep - Z(1) or + bAbs - Z(1) >= infRep - Z(1)) + { + // NaN + anything = qNaN + if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) { + return @bitCast(T, qnanRep); + } + // +/-infinity + anything remaining = +/- infinity + else { + return a; + } + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (aAbs == 0) { + // but we need to get the sign right for zero + zero + if (bAbs == 0) { + return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b)); + } else { + return b; + } + } + + // anything + zero = anything + if (bAbs == 0) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent); + var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent); + var aSignificand = aRep & significandMask; + var bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(T, &aSignificand); + if (bExponent == 0) bExponent = normalize(T, &bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const resultSign = aRep & signBit; + const subtraction = (aRep ^ bRep) & signBit != 0; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const @"align" = @intCast(Z, aExponent - bExponent); + if (@"align" != 0) { + if (@"align" < typeWidth) { + const sticky = if (bSignificand << @intCast(u7, typeWidth - @"align") != 0) Z(1) else 0; + bSignificand = (bSignificand >> @truncate(u7, @"align")) | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + if (subtraction) { + aSignificand -= bSignificand; + // If a == -b, return +zero. + if (aSignificand == 0) return @bitCast(T, Z(0)); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(implicitBit << 3)); + aSignificand <<= @intCast(u7, shift); + aExponent -= shift; + } + } else { // addition + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & (implicitBit << 4) != 0) { + const sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const shift = @intCast(Z, 1 - aExponent); + const sticky = if (aSignificand << @intCast(u7, typeWidth - shift) != 0) Z(1) else 0; + aSignificand = aSignificand >> @intCast(u7, shift | sticky); + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + var result = (aSignificand >> 3) & significandMask; + + // Insert the exponent and sign. + result |= @intCast(Z, aExponent) << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result += 1; + if (roundGuardSticky == 0x4) result += result & 1; + + return @bitCast(T, result); +} + +test "import addXf3" { + _ = @import("addXf3_test.zig"); +} diff --git a/std/special/compiler_rt/addXf3_test.zig b/std/special/compiler_rt/addXf3_test.zig new file mode 100644 index 0000000000..f374a67433 --- /dev/null +++ b/std/special/compiler_rt/addXf3_test.zig @@ -0,0 +1,85 @@ +// Ported from: +// +// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/test/builtins/Unit/addtf3_test.c +// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/test/builtins/Unit/subtf3_test.c + +const qnan128 = @bitCast(f128, u128(0x7fff800000000000) << 64); +const inf128 = @bitCast(f128, u128(0x7fff000000000000) << 64); + +const __addtf3 = @import("addXf3.zig").__addtf3; + +fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void { + const x = __addtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + @panic("__addtf3 test failure"); +} + +test "addtf3" { + test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + test__addtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf + inf = inf + test__addtf3(inf128, inf128, 0x7fff000000000000, 0x0); + + // inf + any = inf + test__addtf3(inf128, 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c); +} + +const __subtf3 = @import("addXf3.zig").__subtf3; + +fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void { + const x = __subtf3(a, b); + + const rep = @bitCast(u128, x); + const hi = @intCast(u64, rep >> 64); + const lo = @truncate(u64, rep); + + if (hi == expected_hi and lo == expected_lo) { + return; + } + // test other possible NaN representation (signal NaN) + else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) { + if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and + ((hi & 0xffffffffffff) > 0 or lo > 0)) + { + return; + } + } + + @panic("__subtf3 test failure"); +} + +test "subtf3" { + // qNaN - any = qNaN + test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // NaN + any = NaN + test__subtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0); + + // inf - any = inf + test__subtf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0); + + // any + any + test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c); +} diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 3df94db589..6715df1805 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -21,6 +21,9 @@ comptime { @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); @@ -37,6 +40,7 @@ comptime { @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); diff --git a/std/special/compiler_rt/truncXfYf2.zig b/std/special/compiler_rt/truncXfYf2.zig index 5cb2f61568..b385090a93 100644 --- a/std/special/compiler_rt/truncXfYf2.zig +++ b/std/special/compiler_rt/truncXfYf2.zig @@ -4,6 +4,10 @@ pub extern fn __truncsfhf2(a: f32) u16 { return @bitCast(u16, truncXfYf2(f16, f32, a)); } +pub extern fn __truncdfhf2(a: f64) u16 { + return @bitCast(u16, truncXfYf2(f16, f64, a)); +} + pub extern fn __trunctfsf2(a: f128) f32 { return truncXfYf2(f32, f128, a); } diff --git a/std/special/compiler_rt/truncXfYf2_test.zig b/std/special/compiler_rt/truncXfYf2_test.zig index c4bf2db733..429372c3f1 100644 --- a/std/special/compiler_rt/truncXfYf2_test.zig +++ b/std/special/compiler_rt/truncXfYf2_test.zig @@ -63,6 +63,74 @@ test "truncsfhf2" { test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero } +const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2; + +fn test__truncdfhf2(a: f64, expected: u16) void { + const rep = @bitCast(u16, __truncdfhf2(a)); + + if (rep == expected) { + return; + } + // test other possible NaN representation(signal NaN) + else if (expected == 0x7e00) { + if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) { + return; + } + } + + @panic("__truncdfhf2 test failure"); +} + +fn test__truncdfhf2_raw(a: u64, expected: u16) void { + const actual = __truncdfhf2(@bitCast(f64, a)); + + if (actual == expected) { + return; + } + + @panic("__truncdfhf2 test failure"); +} + +test "truncdfhf2" { + test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN + test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN + + test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf + test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf + + test__truncdfhf2(0.0, 0x0); // zero + test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero + + test__truncdfhf2(3.1415926535, 0x4248); + test__truncdfhf2(-3.1415926535, 0xc248); + + test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00); + test__truncdfhf2(0x1.987124876876324p+12, 0x6e62); + test__truncdfhf2(0x1.0p+0, 0x3c00); + test__truncdfhf2(0x1.0p-14, 0x0400); + + // denormal + test__truncdfhf2(0x1.0p-20, 0x0010); + test__truncdfhf2(0x1.0p-24, 0x0001); + test__truncdfhf2(-0x1.0p-24, 0x8001); + test__truncdfhf2(0x1.5p-25, 0x0001); + + // and back to zero + test__truncdfhf2(0x1.0p-25, 0x0000); + test__truncdfhf2(-0x1.0p-25, 0x8000); + + // max (precise) + test__truncdfhf2(65504.0, 0x7bff); + + // max (rounded) + test__truncdfhf2(65519.0, 0x7bff); + + // max (to +inf) + test__truncdfhf2(65520.0, 0x7c00); + test__truncdfhf2(-65520.0, 0xfc00); + test__truncdfhf2(65536.0, 0x7c00); +} + const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2; fn test__trunctfsf2(a: f128, expected: u32) void { From cf007e37b95db9faebf34c4c8f9b73aa20eb0672 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Wed, 13 Feb 2019 23:27:23 +1300 Subject: [PATCH 182/218] Add f128 support for fabs, isinf, isnan, inf and nan functions --- std/math/fabs.zig | 19 +++++++++++++++++++ std/math/index.zig | 12 +++++++++++- std/math/inf.zig | 7 ++++--- std/math/isinf.zig | 22 ++++++++++++++++++++++ std/math/isnan.zig | 6 ++++++ std/math/nan.zig | 7 ++++--- 6 files changed, 66 insertions(+), 7 deletions(-) diff --git a/std/math/fabs.zig b/std/math/fabs.zig index 9fad5644c3..a605f4f33f 100644 --- a/std/math/fabs.zig +++ b/std/math/fabs.zig @@ -14,6 +14,7 @@ pub fn fabs(x: var) @typeOf(x) { f16 => fabs16(x), f32 => fabs32(x), f64 => fabs64(x), + f128 => fabs128(x), else => @compileError("fabs not implemented for " ++ @typeName(T)), }; } @@ -36,10 +37,17 @@ fn fabs64(x: f64) f64 { return @bitCast(f64, u); } +fn fabs128(x: f128) f128 { + var u = @bitCast(u128, x); + u &= maxInt(u128) >> 1; + return @bitCast(f128, u); +} + test "math.fabs" { expect(fabs(f16(1.0)) == fabs16(1.0)); expect(fabs(f32(1.0)) == fabs32(1.0)); expect(fabs(f64(1.0)) == fabs64(1.0)); + expect(fabs(f128(1.0)) == fabs128(1.0)); } test "math.fabs16" { @@ -57,6 +65,11 @@ test "math.fabs64" { expect(fabs64(-1.0) == 1.0); } +test "math.fabs128" { + expect(fabs128(1.0) == 1.0); + expect(fabs128(-1.0) == 1.0); +} + test "math.fabs16.special" { expect(math.isPositiveInf(fabs(math.inf(f16)))); expect(math.isPositiveInf(fabs(-math.inf(f16)))); @@ -74,3 +87,9 @@ test "math.fabs64.special" { expect(math.isPositiveInf(fabs(-math.inf(f64)))); expect(math.isNan(fabs(math.nan(f64)))); } + +test "math.fabs128.special" { + expect(math.isPositiveInf(fabs(math.inf(f128)))); + expect(math.isPositiveInf(fabs(-math.inf(f128)))); + expect(math.isNan(fabs(math.nan(f128)))); +} diff --git a/std/math/index.zig b/std/math/index.zig index ccfac03038..20648139b8 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -51,6 +51,12 @@ 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; @@ -379,7 +385,7 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t return u0; } const is_signed = from < 0; - const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement + 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; @@ -752,6 +758,7 @@ test "minInt and maxInt" { 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); @@ -760,6 +767,7 @@ test "minInt and maxInt" { 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); @@ -768,6 +776,7 @@ test "minInt and maxInt" { 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); @@ -776,6 +785,7 @@ test "minInt and maxInt" { testing.expect(minInt(i32) == -2147483648); testing.expect(minInt(i63) == -4611686018427387904); testing.expect(minInt(i64) == -9223372036854775808); + testing.expect(minInt(i128) == -170141183460469231731687303715884105728); } test "max value type" { diff --git a/std/math/inf.zig b/std/math/inf.zig index 62f5ef7c0d..fb7a3489c5 100644 --- a/std/math/inf.zig +++ b/std/math/inf.zig @@ -3,9 +3,10 @@ const math = std.math; pub fn inf(comptime T: type) T { return switch (T) { - f16 => @bitCast(f16, math.inf_u16), - f32 => @bitCast(f32, math.inf_u32), - f64 => @bitCast(f64, math.inf_u64), + f16 => math.inf_f16, + f32 => math.inf_f32, + f64 => math.inf_f64, + f128 => math.inf_f128, else => @compileError("inf not implemented for " ++ @typeName(T)), }; } diff --git a/std/math/isinf.zig b/std/math/isinf.zig index e34e9c5971..b1e3f7795e 100644 --- a/std/math/isinf.zig +++ b/std/math/isinf.zig @@ -18,6 +18,10 @@ pub fn isInf(x: var) bool { const bits = @bitCast(u64, x); return bits & (maxInt(u64) >> 1) == (0x7FF << 52); }, + f128 => { + const bits = @bitCast(u128, x); + return bits & (maxInt(u128) >> 1) == (0x7FFF << 112); + }, else => { @compileError("isInf not implemented for " ++ @typeName(T)); }, @@ -36,6 +40,9 @@ pub fn isPositiveInf(x: var) bool { f64 => { return @bitCast(u64, x) == 0x7FF << 52; }, + f128 => { + return @bitCast(u128, x) == 0x7FFF << 112; + }, else => { @compileError("isPositiveInf not implemented for " ++ @typeName(T)); }, @@ -54,6 +61,9 @@ pub fn isNegativeInf(x: var) bool { f64 => { return @bitCast(u64, x) == 0xFFF << 52; }, + f128 => { + return @bitCast(u128, x) == 0xFFFF << 112; + }, else => { @compileError("isNegativeInf not implemented for " ++ @typeName(T)); }, @@ -67,12 +77,16 @@ test "math.isInf" { expect(!isInf(f32(-0.0))); expect(!isInf(f64(0.0))); expect(!isInf(f64(-0.0))); + expect(!isInf(f128(0.0))); + expect(!isInf(f128(-0.0))); expect(isInf(math.inf(f16))); expect(isInf(-math.inf(f16))); expect(isInf(math.inf(f32))); expect(isInf(-math.inf(f32))); expect(isInf(math.inf(f64))); expect(isInf(-math.inf(f64))); + expect(isInf(math.inf(f128))); + expect(isInf(-math.inf(f128))); } test "math.isPositiveInf" { @@ -82,12 +96,16 @@ test "math.isPositiveInf" { expect(!isPositiveInf(f32(-0.0))); expect(!isPositiveInf(f64(0.0))); expect(!isPositiveInf(f64(-0.0))); + expect(!isPositiveInf(f128(0.0))); + expect(!isPositiveInf(f128(-0.0))); expect(isPositiveInf(math.inf(f16))); expect(!isPositiveInf(-math.inf(f16))); expect(isPositiveInf(math.inf(f32))); expect(!isPositiveInf(-math.inf(f32))); expect(isPositiveInf(math.inf(f64))); expect(!isPositiveInf(-math.inf(f64))); + expect(isPositiveInf(math.inf(f128))); + expect(!isPositiveInf(-math.inf(f128))); } test "math.isNegativeInf" { @@ -97,10 +115,14 @@ test "math.isNegativeInf" { expect(!isNegativeInf(f32(-0.0))); expect(!isNegativeInf(f64(0.0))); expect(!isNegativeInf(f64(-0.0))); + expect(!isNegativeInf(f128(0.0))); + expect(!isNegativeInf(f128(-0.0))); expect(!isNegativeInf(math.inf(f16))); expect(isNegativeInf(-math.inf(f16))); expect(!isNegativeInf(math.inf(f32))); expect(isNegativeInf(-math.inf(f32))); expect(!isNegativeInf(math.inf(f64))); expect(isNegativeInf(-math.inf(f64))); + expect(!isNegativeInf(math.inf(f128))); + expect(isNegativeInf(-math.inf(f128))); } diff --git a/std/math/isnan.zig b/std/math/isnan.zig index 641da9e620..e8b03a1e34 100644 --- a/std/math/isnan.zig +++ b/std/math/isnan.zig @@ -18,6 +18,10 @@ pub fn isNan(x: var) bool { const bits = @bitCast(u64, x); return (bits & (maxInt(u64) >> 1)) > (u64(0x7FF) << 52); }, + f128 => { + const bits = @bitCast(u128, x); + return (bits & (maxInt(u128) >> 1)) > (u128(0x7FFF) << 112); + }, else => { @compileError("isNan not implemented for " ++ @typeName(T)); }, @@ -34,7 +38,9 @@ test "math.isNan" { expect(isNan(math.nan(f16))); expect(isNan(math.nan(f32))); expect(isNan(math.nan(f64))); + expect(isNan(math.nan(f128))); expect(!isNan(f16(1.0))); expect(!isNan(f32(1.0))); expect(!isNan(f64(1.0))); + expect(!isNan(f128(1.0))); } diff --git a/std/math/nan.zig b/std/math/nan.zig index 2cbcbee81b..d3ad43da23 100644 --- a/std/math/nan.zig +++ b/std/math/nan.zig @@ -2,9 +2,10 @@ const math = @import("index.zig"); pub fn nan(comptime T: type) T { return switch (T) { - f16 => @bitCast(f16, math.nan_u16), - f32 => @bitCast(f32, math.nan_u32), - f64 => @bitCast(f64, math.nan_u64), + f16 => math.nan_f16, + f32 => math.nan_f32, + f64 => math.nan_f64, + f128 => math.nan_f128, else => @compileError("nan not implemented for " ++ @typeName(T)), }; } From c221b29c9d3c269326b3d901ce5a8b5f50263feb Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 13 Feb 2019 11:31:13 +0100 Subject: [PATCH 183/218] We already support vector on floats, so let's test it --- test/stage1/behavior/vector.zig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 7cead12b65..5e3e446109 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -15,3 +15,17 @@ test "vector wrap operators" { S.doTheTest(); comptime S.doTheTest(); } + +test "vector float operators" { + const S = struct { + fn doTheTest() void { + const v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; + const x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 }; + expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 })); + expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 })); + expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 })); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From 53297a1bd09d4a4499117c1868d8448f007b12d9 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 13 Feb 2019 11:40:32 +0100 Subject: [PATCH 184/218] We already support vector bit operators, so let's test it --- test/stage1/behavior/vector.zig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 5e3e446109..b0d2871454 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -29,3 +29,17 @@ test "vector float operators" { S.doTheTest(); comptime S.doTheTest(); } + +test "vector bit operators" { + const S = struct { + fn doTheTest() void { + const v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; + const x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; + expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); + expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); + expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From c34ce6878e5834a123be862d45bd26fd9a843eef Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Thu, 14 Feb 2019 00:06:32 +1300 Subject: [PATCH 185/218] Add parseFloat to std.fmt This is not intended to be the long-term implementation as it doesn't provide various properties that we eventually will want (e.g. round-tripping, denormal support). It also uses f64 internally so the wider f128 will be inaccurate. --- CMakeLists.txt | 1 + std/fmt/index.zig | 8 +- std/fmt/parse_float.zig | 425 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 std/fmt/parse_float.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 41fa44374e..8e80c65dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -482,6 +482,7 @@ set(ZIG_STD_FILES "fmt/errol/index.zig" "fmt/errol/lookup.zig" "fmt/index.zig" + "fmt/parse_float.zig" "hash/adler.zig" "hash/crc.zig" "hash/fnv.zig" diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 05b028112f..efb1c41f92 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -828,7 +828,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned return x; } -test "parseUnsigned" { +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)); @@ -855,6 +855,12 @@ test "parseUnsigned" { 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', diff --git a/std/fmt/parse_float.zig b/std/fmt/parse_float.zig new file mode 100644 index 0000000000..b83cdbbbb2 --- /dev/null +++ b/std/fmt/parse_float.zig @@ -0,0 +1,425 @@ +// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat. + +// MIT License +// +// Copyright (c) 2016 Grzegorz Kraszewski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +// Be aware that this implementation has the following limitations: +// +// - Is not round-trip accurate for all values +// - Only supports round-to-zero +// - Does not handle denormals + +const std = @import("../index.zig"); + +const max_digits = 25; + +const f64_plus_zero: u64 = 0x0000000000000000; +const f64_minus_zero: u64 = 0x8000000000000000; +const f64_plus_infinity: u64 = 0x7FF0000000000000; +const f64_minus_infinity: u64 = 0xFFF0000000000000; + +const Z96 = struct { + d0: u32, + d1: u32, + d2: u32, + + // d = s >> 1 + inline fn shiftRight1(d: *Z96, s: Z96) void { + d.d0 = (s.d0 >> 1) | ((s.d1 & 1) << 31); + d.d1 = (s.d1 >> 1) | ((s.d2 & 1) << 31); + d.d2 = s.d2 >> 1; + } + + // d = s << 1 + inline fn shiftLeft1(d: *Z96, s: Z96) void { + d.d2 = (s.d2 << 1) | ((s.d1 & (1 << 31)) >> 31); + d.d1 = (s.d1 << 1) | ((s.d0 & (1 << 31)) >> 31); + d.d0 = s.d0 << 1; + } + + // d += s + inline fn add(d: *Z96, s: Z96) void { + var w = u64(d.d0) + u64(s.d0); + d.d0 = @truncate(u32, w); + + w >>= 32; + w += u64(d.d1) + u64(s.d1); + d.d1 = @truncate(u32, w); + + w >>= 32; + w += u64(d.d2) + u64(s.d2); + d.d2 = @truncate(u32, w); + } + + // d -= s + inline fn sub(d: *Z96, s: Z96) void { + var w = u64(d.d0) -% u64(s.d0); + d.d0 = @truncate(u32, w); + + w >>= 32; + w += u64(d.d1) -% u64(s.d1); + d.d1 = @truncate(u32, w); + + w >>= 32; + w += u64(d.d2) -% u64(s.d2); + d.d2 = @truncate(u32, w); + } + + fn dump(d: Z96) void { + std.debug.warn("{} {} {}\n", d.d0, d.d1, d.d2); + } +}; + +const FloatRepr = struct { + negative: bool, + exponent: i32, + mantissa: u64, +}; + +fn convertRepr(comptime T: type, n: FloatRepr) T { + const mask28: u32 = 0xf << 28; + + var s: Z96 = undefined; + var q: Z96 = undefined; + var r: Z96 = undefined; + + s.d0 = @truncate(u32, n.mantissa); + s.d1 = @truncate(u32, n.mantissa >> 32); + s.d2 = 0; + + var binary_exponent: u64 = 92; + var exp = n.exponent; + + while (exp > 0) : (exp -= 1) { + q.shiftLeft1(s); // q = p << 1 + r.shiftLeft1(q); // r = p << 2 + s.shiftLeft1(r); // p = p << 3 + q.add(s); // p = (p << 3) + (p << 1) + + exp -= 1; + + while (s.d2 & mask28 != 0) { + q.shiftRight1(s); + binary_exponent += 1; + s = q; + } + } + + while (exp < 0) { + while (s.d2 & (1 << 31) == 0) { + q.shiftLeft1(s); + binary_exponent -= 1; + s = q; + } + + q.d2 = s.d2 / 10; + r.d1 = s.d2 % 10; + r.d2 = (s.d1 >> 8) | (r.d1 << 24); + q.d1 = r.d2 / 10; + r.d1 = r.d2 % 10; + r.d2 = ((s.d1 & 0xff) << 16) | (s.d0 >> 16) | (r.d1 << 24); + r.d0 = r.d2 / 10; + r.d1 = r.d2 % 10; + q.d1 = (q.d1 << 8) | ((r.d0 & 0x00ff0000) >> 16); + q.d0 = r.d0 << 16; + r.d2 = (s.d0 *% 0xffff) | (r.d1 << 16); + q.d0 |= r.d2 / 10; + s = q; + + exp += 1; + } + + if (s.d0 != 0 or s.d1 != 0 or s.d2 != 0) { + while (s.d2 & mask28 == 0) { + q.shiftLeft1(s); + binary_exponent -= 1; + s = q; + } + } + + binary_exponent += 1023; + + const repr: u64 = blk: { + if (binary_exponent > 2046) { + break :blk if (n.negative) f64_minus_infinity else f64_plus_infinity; + } else if (binary_exponent < 1) { + break :blk if (n.negative) f64_minus_zero else f64_plus_zero; + } else if (s.d2 != 0) { + const binexs2 = u64(binary_exponent) << 52; + const rr = (u64(s.d2 & ~mask28) << 24) | ((u64(s.d1) + 128) >> 8) | binexs2; + break :blk if (n.negative) rr | (1 << 63) else rr; + } else { + break :blk 0; + } + }; + + const f = @bitCast(f64, repr); + return @floatCast(T, f); +} + +const State = enum { + SkipLeadingWhitespace, + MaybeSign, + LeadingMantissaZeros, + LeadingFractionalZeros, + MantissaIntegral, + MantissaFractional, + ExponentSign, + LeadingExponentZeros, + Exponent, + Stop, +}; + +const ParseResult = enum { + Ok, + PlusZero, + MinusZero, + PlusInf, + MinusInf, +}; + +inline fn isDigit(c: u8) bool { + return c >= '0' and c <= '9'; +} + +inline fn isSpace(c: u8) bool { + return (c >= 0x09 and c <= 0x13) or c == 0x20; +} + +fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { + var digit_index: usize = 0; + var negative = false; + var negative_exp = false; + var exponent: i32 = 0; + + var state = State.SkipLeadingWhitespace; + + var i: usize = 0; + loop: while (state != State.Stop and i < s.len) { + const c = s[i]; + + switch (state) { + State.SkipLeadingWhitespace => { + if (isSpace(c)) { + i += 1; + } else { + state = State.MaybeSign; + } + }, + + State.MaybeSign => { + state = State.LeadingMantissaZeros; + + if (c == '+') { + i += 1; + } else if (c == '-') { + n.negative = true; + i += 1; + } else if (isDigit(c) or c == '.') { + // continue + } else { + state = State.Stop; + } + }, + + State.LeadingMantissaZeros => { + if (c == '0') { + i += 1; + } else if (c == '.') { + i += 1; + state = State.LeadingFractionalZeros; + } else { + state = State.MantissaIntegral; + } + }, + + State.LeadingFractionalZeros => { + if (c == '0') { + i += 1; + if (n.exponent > std.math.minInt(i32)) { + n.exponent -= 1; + } + } else { + state = State.MantissaFractional; + } + }, + + State.MantissaIntegral => { + if (isDigit(c)) { + if (digit_index < max_digits) { + n.mantissa *%= 10; + n.mantissa += s[i] - '0'; + digit_index += 1; + } else if (n.exponent < std.math.maxInt(i32)) { + n.exponent += 1; + } + + i += 1; + } else if (c == '.') { + i += 1; + state = State.MantissaFractional; + } else { + state = State.MantissaFractional; + } + }, + + State.MantissaFractional => { + if (isDigit(c)) { + if (digit_index < max_digits) { + n.mantissa *%= 10; + n.mantissa += c - '0'; + n.exponent -%= 1; + digit_index += 1; + } + + i += 1; + } else if (c == 'e' or c == 'E') { + i += 1; + state = State.ExponentSign; + } else { + state = State.ExponentSign; + } + }, + + State.ExponentSign => { + if (c == '+') { + i += 1; + } else if (c == '-') { + negative_exp = true; + i += 1; + } + + state = State.LeadingExponentZeros; + }, + + State.LeadingExponentZeros => { + if (c == '0') { + i += 1; + } else { + state = State.Exponent; + } + }, + + State.Exponent => { + if (isDigit(c)) { + if (exponent < std.math.maxInt(i32)) { + exponent *= 10; + exponent += @intCast(i32, c - '0'); + } + + i += 1; + } else { + state = State.Stop; + } + }, + + State.Stop => break :loop, + } + } + + if (negative_exp) exponent = -exponent; + n.exponent += exponent; + + if (n.mantissa == 0) { + return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero; + } else if (n.exponent > 309) { + return if (n.negative) ParseResult.MinusInf else ParseResult.PlusInf; + } else if (n.exponent < -328) { + return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero; + } + + return ParseResult.Ok; +} + +inline fn isLower(c: u8) bool { + return c -% 'a' < 26; +} + +inline fn toUpper(c: u8) u8 { + return if (isLower(c)) (c & 0x5f) else c; +} + +fn caseInEql(a: []const u8, b: []const u8) bool { + if (a.len != b.len) return false; + + for (a) |_, i| { + if (toUpper(a[i]) != toUpper(b[i])) { + return false; + } + } + + return true; +} + +pub fn parseFloat(comptime T: type, s: []const u8) T { + var r = FloatRepr{ + .negative = false, + .exponent = 0, + .mantissa = 0, + }; + + if (caseInEql(s, "nan")) { + return std.math.nan(T); + } else if (caseInEql(s, "inf") or caseInEql(s, "+inf")) { + return std.math.inf(T); + } else if (caseInEql(s, "-inf")) { + return -std.math.inf(T); + } + + return switch (parseRepr(s, &r)) { + ParseResult.Ok => convertRepr(T, r), + ParseResult.PlusZero => 0.0, + ParseResult.MinusZero => -T(0.0), + ParseResult.PlusInf => std.math.inf(T), + ParseResult.MinusInf => -std.math.inf(T), + }; +} + +test "fmt.parseFloat" { + const assert = std.debug.assert; + const approxEq = std.math.approxEq; + const epsilon = 1e-7; + + inline for ([]type{ f32, f64, f128 }) |T| { + const Z = @IntType(false, T.bit_count); + + assert(parseFloat(T, "0") == 0.0); + assert(parseFloat(T, "+0") == 0.0); + assert(parseFloat(T, "-0") == 0.0); + + assert(approxEq(T, parseFloat(T, "3.141"), 3.141, epsilon)); + assert(approxEq(T, parseFloat(T, "-3.141"), -3.141, epsilon)); + + assert(parseFloat(T, "1e-700") == 0); + assert(parseFloat(T, "1e+700") == std.math.inf(T)); + + assert(@bitCast(Z, parseFloat(T, "nAn")) == @bitCast(Z, std.math.nan(T))); + assert(parseFloat(T, "inF") == std.math.inf(T)); + assert(parseFloat(T, "-INF") == -std.math.inf(T)); + + if (T != f16) { + assert(approxEq(T, parseFloat(T, "123142.1"), 123142.1, epsilon)); + assert(approxEq(T, parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); + } + } +} From de7c55145aeb6687040254dedaef66eedf5328dd Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Thu, 14 Feb 2019 00:12:00 +1300 Subject: [PATCH 186/218] Add parseFloat support to json.zig --- std/json.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/std/json.zig b/std/json.zig index d8f28560e5..5a28d9ab41 100644 --- a/std/json.zig +++ b/std/json.zig @@ -1345,7 +1345,7 @@ pub const Parser = struct { return if (token.number_is_integer) Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) } else - @panic("TODO: fmt.parseFloat not yet implemented"); + Value{ .Float = std.fmt.parseFloat(f64, token.slice(input, i)) }; } }; @@ -1366,7 +1366,8 @@ test "json.parser.dynamic" { \\ }, \\ "Animated" : false, \\ "IDs": [116, 943, 234, 38793], - \\ "ArrayOfObject": [{"n": "m"}] + \\ "ArrayOfObject": [{"n": "m"}], + \\ "double": 1.3412 \\ } \\} ; @@ -1395,4 +1396,7 @@ test "json.parser.dynamic" { const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; testing.expect(mem.eql(u8, obj0.String, "m")); + + const double = image.Object.get("double").?.value; + testing.expect(double.Float == 1.3412); } From 2911eb34ded4709429a9767e08675ae862907a5f Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 13 Feb 2019 12:19:08 +0100 Subject: [PATCH 187/218] Added error for nesting vectors --- test/compile_errors.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index b47cdf2ed1..b895e2c2d1 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5430,4 +5430,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:7:30: error: unable to evaluate constant expression", ); + + cases.addTest( + "nested vectors", + \\export fn entry() void { + \\ const V = @Vector(4, @Vector(4, u8)); + \\ var v: V = undefined; + \\} + , + ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid", + ); } From d4d2718bca9e23ceec029bb505c0ea1b91c875b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 00:40:39 -0500 Subject: [PATCH 188/218] comptime detection of casting null to pointer See #1059 --- src/ir.cpp | 17 ++++++++++++++--- test/compile_errors.zig | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 19bec193d5..f064adb128 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20645,12 +20645,23 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } if (instr_is_comptime(ptr)) { - // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern - // of the pointer as the new pointer type. - ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); + bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); + UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; + ConstExprValue *val = ir_resolve_const(ira, ptr, is_undef_allowed); if (!val) return ira->codegen->invalid_instruction; + if (val->special == ConstValSpecialStatic) { + bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || + (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + val->data.x_ptr.data.hard_coded_addr.addr == 0); + if (is_addr_zero && !dest_allows_addr_zero) { + ir_add_error(ira, source_instr, + buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + } + IrInstruction *result = ir_const(ira, source_instr, dest_type); copy_const_val(&result->value, val, false); result->value.type = dest_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index c51a65cadf..71ee4901ff 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,26 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting null c pointer to zig pointer", + \\comptime { + \\ var c_ptr: [*c]u8 = 0; + \\ var zig_ptr: *u8 = c_ptr; + \\} + , + ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'", + ); + + cases.addTest( + "implicit casting undefined c pointer to zig pointer", + \\comptime { + \\ var c_ptr: [*c]u8 = undefined; + \\ var zig_ptr: *u8 = c_ptr; + \\} + , + ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior", + ); + cases.addTest( "implicit casting C pointers which would mess up null semantics", \\export fn entry() void { From 59de24817e8538434f35a20a401f40c2f0231a9a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 01:09:33 -0500 Subject: [PATCH 189/218] runtime safety check for casting null to pointer see #1059 --- src/all_types.hpp | 3 +++ src/analyze.cpp | 9 +++++++ src/analyze.hpp | 1 + src/codegen.cpp | 19 ++++++++++++++- src/ir.cpp | 52 ++++++++++++++++++++--------------------- test/runtime_safety.zig | 10 ++++++++ 6 files changed, 67 insertions(+), 27 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 230dba9a42..bafe316c3d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1488,6 +1488,7 @@ enum PanicMsgId { PanicMsgIdBadUnionField, PanicMsgIdBadEnumValue, PanicMsgIdFloatToInt, + PanicMsgIdPtrCastNull, PanicMsgIdCount, }; @@ -3001,12 +3002,14 @@ struct IrInstructionPtrCastSrc { IrInstruction *dest_type; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionPtrCastGen { IrInstruction base; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionBitCast { diff --git a/src/analyze.cpp b/src/analyze.cpp index 900def52d4..6a8090a843 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6902,3 +6902,12 @@ const char *container_string(ContainerKind kind) { } zig_unreachable(); } + +bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index c8141b02ff..50e841baa1 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -45,6 +45,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); +bool ptr_allows_addr_zero(ZigType *ptr_type); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/codegen.cpp b/src/codegen.cpp index 142e8174f5..dbb13ca885 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -950,6 +950,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("invalid enum value"); case PanicMsgIdFloatToInt: return buf_create_from_str("integer part of floating point value out of bounds"); + case PanicMsgIdPtrCastNull: + return buf_create_from_str("cast causes pointer to be null"); } zig_unreachable(); } @@ -3028,7 +3030,22 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, return nullptr; } LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); + if (!want_safety_check || ptr_allows_addr_zero(wanted_type)) + return result_ptr; + + LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr)); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, ""); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdPtrCastNull); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return result_ptr; } static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, diff --git a/src/ir.cpp b/src/ir.cpp index f064adb128..dfbc36e02c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -172,7 +172,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src); + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); @@ -2202,12 +2202,13 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo } static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *ptr) + IrInstruction *dest_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastSrc *instruction = ir_build_instruction( irb, scope, source_node); instruction->dest_type = dest_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -2216,12 +2217,13 @@ static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, - ZigType *ptr_type, IrInstruction *ptr) + ZigType *ptr_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastGen *instruction = ir_build_instruction( &ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ptr_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); @@ -4505,7 +4507,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); return ir_lval_wrap(irb, scope, ptr_cast, lval); } case BuiltinFnIdBitCast: @@ -6740,7 +6742,8 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6818,7 +6821,8 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -7363,7 +7367,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, + coro_promise_ptr, false); coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); @@ -7387,7 +7392,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr, + false); irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); @@ -7465,9 +7471,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); - IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); - IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, - irb->exec->coro_result_field_ptr); + IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + result_ptr, false); + IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, + u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false); IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, fn_entry->type_entry->data.fn.fn_type_id.return_type); IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); @@ -7517,7 +7524,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + coro_mem_ptr_maybe, false); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); @@ -8644,15 +8652,6 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } -static bool ptr_allows_addr_zero(ZigType *ptr_type) { - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.allow_zero; - } else if (ptr_type->id == ZigTypeIdOptional) { - return true; - } - return false; -} - static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) { @@ -11310,7 +11309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes && get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type)) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } } @@ -11352,7 +11351,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } // cast from integer to C pointer @@ -20616,7 +20615,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 } static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src) + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on) { Error err; @@ -20685,7 +20684,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return ira->codegen->invalid_instruction; } - IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); + IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -20722,7 +20721,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); + return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value, + instruction->safety_check_on); } static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 821328b7a6..12cac64b3a 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { + cases.addRuntimeSafety("pointer casting null to non-optional pointer", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var c_ptr: [*c]u8 = 0; + \\ var zig_ptr: *u8 = c_ptr; + \\} + ); + cases.addRuntimeSafety("@intToEnum - no matching tag value", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); From a4e32d9fb143dbfb622a5097ea4a1e4bcad03463 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 09:46:08 -0500 Subject: [PATCH 190/218] ci: freebsd: remove '.git' from URL as per upstream suggestion https://todo.sr.ht/~sircmpwn/dispatch.sr.ht/24#comment-1465 --- .builds/freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 934b8a4f4a..5e94a83a3a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -4,7 +4,7 @@ packages: - ninja - llvm70 sources: - - https://github.com/ziglang/zig.git + - https://github.com/ziglang/zig tasks: - build: | cd zig && mkdir build && cd build From c58b80203443dcbf8b737ebdaa1f17fb20c77711 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 10:51:59 -0500 Subject: [PATCH 191/218] remove the "top of the comptime stack" compile error It's still best practice to put `@setEvalBranchQuota` at the top of the comptime stack, but as Jimmi notes in #1949, when a function can be called at comptime and also can be the top of the comptime stack, this compile error is fundamentally unsound. So now it's gone. closes #1949 --- src/ir.cpp | 6 ------ test/compile_errors.zig | 14 -------------- 2 files changed, 20 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 5d4013b4b9..03dea10b10 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18172,12 +18172,6 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, IrInstructionSetEvalBranchQuota *instruction) { - if (ira->new_irb.exec->parent_exec != nullptr && !ira->new_irb.exec->is_generic_instantiation) { - ir_add_error(ira, &instruction->base, - buf_sprintf("@setEvalBranchQuota must be called from the top of the comptime stack")); - return ira->codegen->invalid_instruction; - } - uint64_t new_quota; if (!ir_resolve_usize(ira, instruction->new_quota->child, &new_quota)) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index b895e2c2d1..6a2ded1844 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -4554,20 +4554,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal", ); - cases.add( - "@setEvalBranchQuota in non-root comptime execution context", - \\comptime { - \\ foo(); - \\} - \\fn foo() void { - \\ @setEvalBranchQuota(1001); - \\} - , - ".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack", - ".tmp_source.zig:2:8: note: called from here", - ".tmp_source.zig:1:10: note: called from here", - ); - cases.add( "wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); From e03c770145b5dc7b428d53b3cac97c2733fb84d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 12:28:50 -0500 Subject: [PATCH 192/218] compile error tests for implicit C pointer casting See #1059 --- src/ir.cpp | 38 ++++++++++++++++++-------------------- test/compile_errors.zig | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index dfbc36e02c..89528db185 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8683,16 +8683,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted bool actual_opt_or_ptr = actual_ptr_type != nullptr && (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); if (wanted_opt_or_ptr && actual_opt_or_ptr) { - bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || - (!wanted_allows_zero && !actual_allows_zero); - if (!ok_allows_zero) { - result.id = ConstCastResultIdBadAllowsZero; - result.data.bad_allows_zero = allocate_nonzero(1); - result.data.bad_allows_zero->wanted_type = wanted_type; - result.data.bad_allows_zero->actual_type = actual_type; - return result; - } ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -8705,6 +8695,16 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; return result; } + bool ok_allows_zero = (wanted_allows_zero && + (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (!wanted_allows_zero && !actual_allows_zero); + if (!ok_allows_zero) { + result.id = ConstCastResultIdBadAllowsZero; + result.data.bad_allows_zero = allocate_nonzero(1); + result.data.bad_allows_zero->wanted_type = wanted_type; + result.data.bad_allows_zero->actual_type = actual_type; + return result; + } if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; @@ -10846,22 +10846,20 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa break; } case ConstCastResultIdBadAllowsZero: { - bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type); - ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type); - ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type); - ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type; - ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type; + ZigType *wanted_type = cast_result->data.bad_allows_zero->wanted_type; + ZigType *actual_type = cast_result->data.bad_allows_zero->actual_type; + bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(actual_type); if (actual_allows_zero && !wanted_allows_zero) { add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("'%s' could have null values which are illegal in type '%s'", - buf_ptr(&actual_elem_type->name), - buf_ptr(&wanted_elem_type->name))); + buf_ptr(&actual_type->name), + buf_ptr(&wanted_type->name))); } else { add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", - buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name), - buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name))); + buf_ptr(&wanted_type->name), + buf_ptr(&actual_type->name))); } break; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 71ee4901ff..630386aa4f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,42 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit cast between C pointer and Zig pointer - bad const/align/child", + \\export fn a() void { + \\ var x: [*c]u8 = undefined; + \\ var y: *align(4) u8 = x; + \\} + \\export fn b() void { + \\ var x: [*c]const u8 = undefined; + \\ var y: *u8 = x; + \\} + \\export fn c() void { + \\ var x: [*c]u8 = undefined; + \\ var y: *u32 = x; + \\} + \\export fn d() void { + \\ var y: *align(1) u32 = undefined; + \\ var x: [*c]u32 = y; + \\} + \\export fn e() void { + \\ var y: *const u8 = undefined; + \\ var x: [*c]u8 = y; + \\} + \\export fn f() void { + \\ var y: *u8 = undefined; + \\ 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'", + ); + cases.addTest( "implicit casting null c pointer to zig pointer", \\comptime { @@ -39,6 +75,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , ".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]const [*c]u8', found '*[*]u8'", ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", From 52c03de5c2495b369ae730ff203e5342e4f33a36 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 13:07:51 -0500 Subject: [PATCH 193/218] add missing compile error for OpaqueType inside structs/unions closes #1862 --- src/analyze.cpp | 14 ++++++++++++++ test/compile_errors.zig | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 6a8090a843..90ce3d3371 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2679,6 +2679,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { buf_sprintf("enums, not structs, support field assignment")); } + if (field_type->id == ZigTypeIdOpaque) { + add_node_error(g, field_node->data.struct_field.type, + buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + continue; + } + switch (type_requires_comptime(g, field_type)) { case ReqCompTimeYes: struct_type->data.structure.requires_comptime = true; @@ -2963,6 +2970,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } union_field->type_entry = field_type; + if (field_type->id == ZigTypeIdOpaque) { + add_node_error(g, field_node->data.struct_field.type, + buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.is_invalid = true; + continue; + } + switch (type_requires_comptime(g, field_type)) { case ReqCompTimeInvalid: union_type->data.unionation.is_invalid = true; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 630386aa4f..ac8d413d2c 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,27 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "directly embedding opaque type in struct and union", + \\const O = @OpaqueType(); + \\const Foo = struct { + \\ o: O, + \\}; + \\const Bar = union { + \\ One: i32, + \\ Two: O, + \\}; + \\export fn a() void { + \\ var foo: Foo = undefined; + \\} + \\export fn b() 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", + ); + cases.addTest( "implicit cast between C pointer and Zig pointer - bad const/align/child", \\export fn a() void { From 6769183a9d5f5ec69747f46d4d13c0f8709b2f46 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 15:48:28 -0500 Subject: [PATCH 194/218] fix implicit cast error unions with non-optional to optional pointer and update self hosted compiler for C pointers See #1059 --- doc/docgen.zig | 1 + src-self-hosted/codegen.zig | 42 +++---- src-self-hosted/compilation.zig | 22 ++-- src-self-hosted/ir.zig | 20 ++-- src-self-hosted/llvm.zig | 181 +++++++++++++++++++++--------- src-self-hosted/scope.zig | 2 +- src-self-hosted/target.zig | 4 +- src-self-hosted/type.zig | 42 +++---- src-self-hosted/value.zig | 16 +-- src/ir.cpp | 2 +- std/hash_map.zig | 2 + test/compile_errors.zig | 8 +- test/stage1/behavior/pointers.zig | 17 +++ 13 files changed, 228 insertions(+), 131 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 45f6dc2684..082f308a57 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok std.zig.Token.Id.AngleBracketAngleBracketRightEqual, std.zig.Token.Id.Tilde, std.zig.Token.Id.BracketStarBracket, + std.zig.Token.Id.BracketStarCBracket, => try writeEscaped(out, src[token.start..token.end]), std.zig.Token.Id.Invalid => return parseError( diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 45cfa98942..1c671b61e2 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) pub const ObjectFile = struct { comp: *Compilation, - module: llvm.ModuleRef, - builder: llvm.BuilderRef, + module: *llvm.Module, + builder: *llvm.Builder, dibuilder: *llvm.DIBuilder, - context: llvm.ContextRef, + context: *llvm.Context, lock: event.Lock, arena: *std.mem.Allocator, @@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) fn addLLVMAttr( ofile: *ObjectFile, - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, ) !void { @@ -335,7 +335,7 @@ fn addLLVMAttr( fn addLLVMAttrStr( ofile: *ObjectFile, - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, attr_val: []const u8, @@ -351,7 +351,7 @@ fn addLLVMAttrStr( } fn addLLVMAttrInt( - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, attr_val: u64, @@ -362,25 +362,25 @@ fn addLLVMAttrInt( llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); } -fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void { +fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void { return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name); } -fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void { +fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void { return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); } -fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void { +fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void { return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); } fn renderLoadUntyped( ofile: *ObjectFile, - ptr: llvm.ValueRef, + ptr: *llvm.Value, alignment: Type.Pointer.Align, vol: Type.Pointer.Vol, name: [*]const u8, -) !llvm.ValueRef { +) !*llvm.Value { const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; switch (vol) { Type.Pointer.Vol.Non => {}, @@ -390,11 +390,11 @@ fn renderLoadUntyped( return result; } -fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef { +fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value { return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); } -pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef { +pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value { const child_type = ptr_type.key.child_type; if (!child_type.hasBits()) { return null; @@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po pub fn renderStoreUntyped( ofile: *ObjectFile, - value: llvm.ValueRef, - ptr: llvm.ValueRef, + value: *llvm.Value, + ptr: *llvm.Value, alignment: Type.Pointer.Align, vol: Type.Pointer.Vol, -) !llvm.ValueRef { +) !*llvm.Value { const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory; switch (vol) { Type.Pointer.Vol.Non => {}, @@ -423,10 +423,10 @@ pub fn renderStoreUntyped( pub fn renderStore( ofile: *ObjectFile, - value: llvm.ValueRef, - ptr: llvm.ValueRef, + value: *llvm.Value, + ptr: *llvm.Value, ptr_type: *Type.Pointer, -) !llvm.ValueRef { +) !*llvm.Value { return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol); } @@ -435,7 +435,7 @@ pub fn renderAlloca( var_type: *Type, name: []const u8, alignment: Type.Pointer.Align, -) !llvm.ValueRef { +) !*llvm.Value { const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); const name_with_null = try std.cstr.addNullByte(ofile.arena, name); const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory; @@ -443,7 +443,7 @@ pub fn renderAlloca( return result; } -pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 { +pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 { return switch (alignment) { Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type), Type.Pointer.Align.Override => |a| a, diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index e55d8ccda6..de956f1525 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB /// Data that is local to the event loop. pub const ZigCompiler = struct { loop: *event.Loop, - llvm_handle_pool: std.atomic.Stack(llvm.ContextRef), + llvm_handle_pool: std.atomic.Stack(*llvm.Context), lld_lock: event.Lock, /// TODO pool these so that it doesn't have to lock @@ -60,7 +60,7 @@ pub const ZigCompiler = struct { return ZigCompiler{ .loop = loop, .lld_lock = event.Lock.init(loop), - .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), + .llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(), .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), .native_libc = event.Future(LibCInstallation).init(loop), }; @@ -70,7 +70,7 @@ pub const ZigCompiler = struct { fn deinit(self: *ZigCompiler) void { self.lld_lock.deinit(); while (self.llvm_handle_pool.pop()) |node| { - c.LLVMContextDispose(node.data); + llvm.ContextDispose(node.data); self.loop.allocator.destroy(node); } } @@ -80,11 +80,11 @@ pub const ZigCompiler = struct { pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle { if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node }; - const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; - errdefer c.LLVMContextDispose(context_ref); + const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory; + errdefer llvm.ContextDispose(context_ref); - const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node); - node.* = std.atomic.Stack(llvm.ContextRef).Node{ + const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node); + node.* = std.atomic.Stack(*llvm.Context).Node{ .next = undefined, .data = context_ref, }; @@ -114,7 +114,7 @@ pub const ZigCompiler = struct { }; pub const LlvmHandle = struct { - node: *std.atomic.Stack(llvm.ContextRef).Node, + node: *std.atomic.Stack(*llvm.Context).Node, pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void { zig_compiler.llvm_handle_pool.push(self.node); @@ -128,7 +128,7 @@ pub const Compilation = struct { llvm_triple: Buffer, root_src_path: ?[]const u8, target: Target, - llvm_target: llvm.TargetRef, + llvm_target: *llvm.Target, build_mode: builtin.Mode, zig_lib_dir: []const u8, zig_std_dir: []const u8, @@ -212,8 +212,8 @@ pub const Compilation = struct { false_value: *Value.Bool, noreturn_value: *Value.NoReturn, - target_machine: llvm.TargetMachineRef, - target_data_ref: llvm.TargetDataRef, + target_machine: *llvm.TargetMachine, + target_data_ref: *llvm.TargetData, target_layout_str: [*]u8, target_ptr_bits: u32, diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 0362bb4ef8..dc1b0dc943 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -67,7 +67,7 @@ pub const Inst = struct { parent: ?*Inst, /// populated durign codegen - llvm_value: ?llvm.ValueRef, + llvm_value: ?*llvm.Value, pub fn cast(base: *Inst, comptime T: type) ?*T { if (base.id == comptime typeToId(T)) { @@ -129,7 +129,7 @@ pub const Inst = struct { } } - pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { + pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) { switch (base.id) { Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val), Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val), @@ -313,10 +313,10 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const fn_ref = self.params.fn_ref.llvm_value.?; - const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len); + const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len); for (self.params.args) |arg, i| { args[i] = arg.llvm_value.?; } @@ -360,7 +360,7 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { return self.base.val.KnownValue.getLlvmConst(ofile); } }; @@ -392,7 +392,7 @@ pub const Inst = struct { return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value }); } - pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const value = self.params.return_value.llvm_value; const return_type = self.params.return_value.getKnownType(); @@ -540,7 +540,7 @@ pub const Inst = struct { } } - pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef { + pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value { switch (self.params.var_scope.data) { Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass Scope.Var.Data.Param => |param| return param.llvm_value, @@ -596,7 +596,7 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const child_type = self.base.getKnownType(); if (!child_type.hasBits()) { return null; @@ -935,8 +935,8 @@ pub const BasicBlock = struct { ref_instruction: ?*Inst, /// for codegen - llvm_block: llvm.BasicBlockRef, - llvm_exit_block: llvm.BasicBlockRef, + llvm_block: *llvm.BasicBlock, + llvm_exit_block: *llvm.BasicBlock, /// the basic block that is derived from this one in analysis child: ?*BasicBlock, diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 778d3fae07..704e83c3c6 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -11,45 +11,31 @@ const assert = @import("std").debug.assert; pub const AttributeIndex = c_uint; pub const Bool = c_int; -pub const BuilderRef = removeNullability(c.LLVMBuilderRef); -pub const ContextRef = removeNullability(c.LLVMContextRef); -pub const ModuleRef = removeNullability(c.LLVMModuleRef); -pub const ValueRef = removeNullability(c.LLVMValueRef); -pub const TypeRef = removeNullability(c.LLVMTypeRef); -pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); -pub const AttributeRef = removeNullability(c.LLVMAttributeRef); -pub const TargetRef = removeNullability(c.LLVMTargetRef); -pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef); -pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef); +pub const Builder = c.LLVMBuilderRef.Child; +pub const Context = c.LLVMContextRef.Child; +pub const Module = c.LLVMModuleRef.Child; +pub const Value = c.LLVMValueRef.Child; +pub const Type = c.LLVMTypeRef.Child; +pub const BasicBlock = c.LLVMBasicBlockRef.Child; +pub const Attribute = c.LLVMAttributeRef.Child; +pub const Target = c.LLVMTargetRef.Child; +pub const TargetMachine = c.LLVMTargetMachineRef.Child; +pub const TargetData = c.LLVMTargetDataRef.Child; pub const DIBuilder = c.ZigLLVMDIBuilder; +pub const DIFile = c.ZigLLVMDIFile; +pub const DICompileUnit = c.ZigLLVMDICompileUnit; pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType; pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; -pub const AddFunction = c.LLVMAddFunction; -pub const AddGlobal = c.LLVMAddGlobal; pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; -pub const ArrayType = c.LLVMArrayType; -pub const BuildLoad = c.LLVMBuildLoad; pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; pub const ConstAllOnes = c.LLVMConstAllOnes; pub const ConstArray = c.LLVMConstArray; pub const ConstBitCast = c.LLVMConstBitCast; -pub const ConstInt = c.LLVMConstInt; pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; pub const ConstNeg = c.LLVMConstNeg; -pub const ConstNull = c.LLVMConstNull; -pub const ConstStringInContext = c.LLVMConstStringInContext; pub const ConstStructInContext = c.LLVMConstStructInContext; -pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData; -pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; -pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit; -pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder; -pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute; -pub const CreateFile = c.ZigLLVMCreateFile; -pub const CreateStringAttribute = c.LLVMCreateStringAttribute; -pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout; -pub const CreateTargetMachine = c.LLVMCreateTargetMachine; pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize; pub const DisposeBuilder = c.LLVMDisposeBuilder; pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder; @@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule; pub const FP128TypeInContext = c.LLVMFP128TypeInContext; pub const FloatTypeInContext = c.LLVMFloatTypeInContext; pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; -pub const GetHostCPUName = c.ZigLLVMGetHostCPUName; pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; -pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures; pub const GetUndef = c.LLVMGetUndef; pub const HalfTypeInContext = c.LLVMHalfTypeInContext; pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers; @@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext; pub const Int8TypeInContext = c.LLVMInt8TypeInContext; pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext; pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext; -pub const IntTypeInContext = c.LLVMIntTypeInContext; pub const LabelTypeInContext = c.LLVMLabelTypeInContext; pub const MDNodeInContext = c.LLVMMDNodeInContext; pub const MDStringInContext = c.LLVMMDStringInContext; pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; -pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; -pub const PointerType = c.LLVMPointerType; pub const SetAlignment = c.LLVMSetAlignment; pub const SetDataLayout = c.LLVMSetDataLayout; pub const SetGlobalConstant = c.LLVMSetGlobalConstant; @@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr; pub const SetVolatile = c.LLVMSetVolatile; pub const StructTypeInContext = c.LLVMStructTypeInContext; pub const TokenTypeInContext = c.LLVMTokenTypeInContext; -pub const VoidTypeInContext = c.LLVMVoidTypeInContext; pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; +pub const AddGlobal = LLVMAddGlobal; +extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value; + +pub const ConstStringInContext = LLVMConstStringInContext; +extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; + +pub const ConstInt = LLVMConstInt; +extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; + +pub const BuildLoad = LLVMBuildLoad; +extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value; + +pub const ConstNull = LLVMConstNull; +extern fn LLVMConstNull(Ty: *Type) ?*Value; + +pub const CreateStringAttribute = LLVMCreateStringAttribute; +extern fn LLVMCreateStringAttribute( + C: *Context, + K: [*]const u8, + KLength: c_uint, + V: [*]const u8, + VLength: c_uint, +) ?*Attribute; + +pub const CreateEnumAttribute = LLVMCreateEnumAttribute; +extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute; + +pub const AddFunction = LLVMAddFunction; +extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value; + +pub const CreateCompileUnit = ZigLLVMCreateCompileUnit; +extern fn ZigLLVMCreateCompileUnit( + dibuilder: *DIBuilder, + lang: c_uint, + difile: *DIFile, + producer: [*]const u8, + is_optimized: bool, + flags: [*]const u8, + runtime_version: c_uint, + split_name: [*]const u8, + dwo_id: u64, + emit_debug_info: bool, +) ?*DICompileUnit; + +pub const CreateFile = ZigLLVMCreateFile; +extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile; + +pub const ArrayType = LLVMArrayType; +extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type; + +pub const CreateDIBuilder = ZigLLVMCreateDIBuilder; +extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder; + +pub const PointerType = LLVMPointerType; +extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type; + +pub const CreateBuilderInContext = LLVMCreateBuilderInContext; +extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder; + +pub const IntTypeInContext = LLVMIntTypeInContext; +extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type; + +pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext; +extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module; + +pub const VoidTypeInContext = LLVMVoidTypeInContext; +extern fn LLVMVoidTypeInContext(C: *Context) ?*Type; + +pub const ContextCreate = LLVMContextCreate; +extern fn LLVMContextCreate() ?*Context; + +pub const ContextDispose = LLVMContextDispose; +extern fn LLVMContextDispose(C: *Context) void; + +pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData; +extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8; + +pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout; +extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; + +pub const CreateTargetMachine = LLVMCreateTargetMachine; +extern fn LLVMCreateTargetMachine( + T: *Target, + Triple: [*]const u8, + CPU: [*]const u8, + Features: [*]const u8, + Level: CodeGenOptLevel, + Reloc: RelocMode, + CodeModel: CodeModel, +) ?*TargetMachine; + +pub const GetHostCPUName = LLVMGetHostCPUName; +extern fn LLVMGetHostCPUName() ?[*]u8; + +pub const GetNativeFeatures = ZigLLVMGetNativeFeatures; +extern fn ZigLLVMGetNativeFeatures() ?[*]u8; + pub const GetElementType = LLVMGetElementType; -extern fn LLVMGetElementType(Ty: TypeRef) TypeRef; +extern fn LLVMGetElementType(Ty: *Type) *Type; pub const TypeOf = LLVMTypeOf; -extern fn LLVMTypeOf(Val: ValueRef) TypeRef; +extern fn LLVMTypeOf(Val: *Value) *Type; pub const BuildStore = LLVMBuildStore; -extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef; +extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value; pub const BuildAlloca = LLVMBuildAlloca; -extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef; +extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value; pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; -pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef; +pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value; pub const GetTargetFromTriple = LLVMGetTargetFromTriple; -extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool; +extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool; pub const VerifyModule = LLVMVerifyModule; -extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; +extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; pub const GetInsertBlock = LLVMGetInsertBlock; -extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef; +extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock; pub const FunctionType = LLVMFunctionType; extern fn LLVMFunctionType( - ReturnType: TypeRef, - ParamTypes: [*]TypeRef, + ReturnType: *Type, + ParamTypes: [*]*Type, ParamCount: c_uint, IsVarArg: Bool, -) ?TypeRef; +) ?*Type; pub const GetParam = LLVMGetParam; -extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef; +extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value; pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; -extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef; +extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock; pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; -extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void; +extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void; pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction; pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; @@ -190,17 +267,17 @@ pub const FnInline = extern enum { }; fn removeNullability(comptime T: type) type { - comptime assert(@typeId(T) == builtin.TypeId.Optional); - return T.Child; + comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C); + return *T.Child; } pub const BuildRet = LLVMBuildRet; -extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef; +extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value; pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; extern fn ZigLLVMTargetMachineEmitToFile( - targ_machine_ref: TargetMachineRef, - module_ref: ModuleRef, + targ_machine_ref: *TargetMachine, + module_ref: *Module, filename: [*]const u8, output_type: EmitOutputType, error_message: *[*]u8, @@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile( ) bool; pub const BuildCall = ZigLLVMBuildCall; -extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef; +extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value; pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig index b14c073a9e..9a84ad256e 100644 --- a/src-self-hosted/scope.zig +++ b/src-self-hosted/scope.zig @@ -362,7 +362,7 @@ pub const Scope = struct { pub const Param = struct { index: usize, typ: *Type, - llvm_value: llvm.ValueRef, + llvm_value: *llvm.Value, }; pub fn createParam( diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 36381b820d..121242b505 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -457,8 +457,8 @@ pub const Target = union(enum) { } } - pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef { - var result: llvm.TargetRef = undefined; + pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target { + var result: *llvm.Target = undefined; var err_msg: [*]u8 = undefined; if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) { std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 790b51b7be..7d611bb787 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -51,8 +51,8 @@ pub const Type = struct { pub fn getLlvmType( base: *Type, allocator: *Allocator, - llvm_context: llvm.ContextRef, - ) (error{OutOfMemory}!llvm.TypeRef) { + llvm_context: *llvm.Context, + ) (error{OutOfMemory}!*llvm.Type) { switch (base.id) { Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), @@ -196,7 +196,7 @@ pub const Type = struct { } /// If you have an llvm conext handy, you can use it here. - pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { + pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*; base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable); @@ -205,7 +205,7 @@ pub const Type = struct { } /// Lower level function that does the work. See getAbiAlignment. - async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { + async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); } @@ -218,7 +218,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -496,13 +496,13 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const normal = &self.key.data.Normal; const llvm_return_type = switch (normal.return_type.id) { Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory, else => try normal.return_type.getLlvmType(allocator, llvm_context), }; - const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len); + const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len); defer allocator.free(llvm_param_types); for (llvm_param_types) |*llvm_param_type, i| { llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context); @@ -559,7 +559,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -658,7 +658,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory; } }; @@ -670,7 +670,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -836,7 +836,7 @@ pub const Type = struct { return self; } - pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context); return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory; } @@ -904,7 +904,7 @@ pub const Type = struct { return self; } - pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context); return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory; } @@ -917,7 +917,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -967,7 +967,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -979,7 +979,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -991,7 +991,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1003,7 +1003,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1015,7 +1015,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1035,7 +1035,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1055,7 +1055,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1067,7 +1067,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 9431c614b9..d9d4c3d1d9 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -57,7 +57,7 @@ pub const Value = struct { std.debug.warn("{}", @tagName(base.id)); } - pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) { + pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) { switch (base.id) { Id.Type => unreachable, Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile), @@ -153,7 +153,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, @@ -238,7 +238,7 @@ pub const Value = struct { /// We know that the function definition will end up in an .o file somewhere. /// Here, all we have to do is generate a global prototype. /// TODO cache the prototype per ObjectFile - pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, @@ -283,7 +283,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { + pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?*llvm.Value { const llvm_type = llvm.Int1TypeInContext(ofile.context); if (self.x) { return llvm.ConstAllOnes(llvm_type); @@ -381,7 +381,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value { const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context); // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr switch (self.special) { @@ -391,7 +391,7 @@ pub const Value = struct { const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; const ptr_bit_count = ofile.comp.target_ptr_bits; const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; - const indices = []llvm.ValueRef{ + const indices = []*llvm.Value{ llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, }; @@ -459,7 +459,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value { switch (self.special) { Special.Undefined => { const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); @@ -534,7 +534,7 @@ pub const Value = struct { return self; } - pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value { switch (self.base.typ.id) { Type.Id.Int => { const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context); diff --git a/src/ir.cpp b/src/ir.cpp index 89528db185..7c46b21717 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8696,7 +8696,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted return result; } bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (actual_allows_zero || !wanted_is_mutable)) || (!wanted_allows_zero && !actual_allows_zero); if (!ok_allows_zero) { result.id = ConstCastResultIdBadAllowsZero; diff --git a/std/hash_map.zig b/std/hash_map.zig index 716f04ff34..4519890bb7 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"), + builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"), builtin.TypeInfo.Pointer.Size.Slice => { const interval = std.math.max(1, key.len / 256); var i: usize = 0; @@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"), + builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"), builtin.TypeInfo.Pointer.Size.Slice => { if (a.len != b.len) return false; for (a) |a_item, i| { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ac8d413d2c..5e9b691641 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -92,15 +92,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var slice: []u8 = &buf; \\ var opt_many_ptr: [*]u8 = slice.ptr; \\ var ptr_opt_many_ptr = &opt_many_ptr; - \\ var c_ptr: [*c]const [*c]u8 = ptr_opt_many_ptr; + \\ 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]const [*c]u8', found '*[*]u8'", - ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", - ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]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'", ); cases.addTest( diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 8d87fe2a20..eed7a765d7 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -1,5 +1,6 @@ const std = @import("std"); const expect = std.testing.expect; +const expectError = std.testing.expectError; test "dereference pointer" { comptime testDerefPtr(); @@ -107,3 +108,19 @@ test "implicit casting between C pointer and optional non-C pointer" { ptr_opt_many_ptr = c_ptr; expect(ptr_opt_many_ptr.*.?[1] == 'o'); } + +test "implicit cast error unions with non-optional to optional pointer" { + const S = struct { + fn doTheTest() void { + expectError(error.Fail, foo()); + } + fn foo() anyerror!?*u8 { + return bar() orelse error.Fail; + } + fn bar() ?*u8 { + return null; + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From df87044fd6588452755014d5909e0db1b776deb2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 16:10:12 -0500 Subject: [PATCH 195/218] omit nonnull attribute for C pointers See #1059 --- src/analyze.cpp | 4 ++++ src/analyze.hpp | 1 + src/codegen.cpp | 19 ++++++++++++++++--- src/target.cpp | 4 ++++ src/target.hpp | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 90ce3d3371..55deafb3a8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4100,6 +4100,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) { return ty; } +bool type_is_nonnull_ptr(ZigType *type) { + return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type); +} + bool type_is_codegen_pointer(ZigType *type) { return get_codegen_ptr_type(type) == type; } diff --git a/src/analyze.hpp b/src/analyze.hpp index 50e841baa1..845fb62534 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -46,6 +46,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); 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); diff --git a/src/codegen.cpp b/src/codegen.cpp index dbb13ca885..bae9abe06d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -617,9 +617,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { unsigned init_gen_i = 0; if (!type_has_bits(return_type)) { // nothing to do - } else if (type_is_codegen_pointer(return_type)) { + } else if (type_is_nonnull_ptr(return_type)) { addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { + // Sret pointers must not be address 0 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); if (cc_want_sret_attr(cc)) { @@ -637,6 +638,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); if (err_ret_trace_arg_index != UINT32_MAX) { + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull"); } @@ -1246,6 +1249,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); @@ -1320,9 +1325,13 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); @@ -1450,6 +1459,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); @@ -2051,7 +2062,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ case FnWalkIdAttrs: { ZigType *ptr_type = get_codegen_ptr_type(ty); if (ptr_type != nullptr) { - if (ty->id != ZigTypeIdOptional) { + if (type_is_nonnull_ptr(ty)) { addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); } if (ptr_type->data.pointer.is_const) { @@ -2095,6 +2106,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ assert(handle_is_ptr(ty)); switch (fn_walk->id) { case FnWalkIdAttrs: + // arrays passed to C ABI functions may not be at address 0 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); fn_walk->data.attrs.gen_i += 1; @@ -2134,6 +2146,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ case FnWalkIdAttrs: addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval"); addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); + // Byvalue parameters must not have address 0 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); fn_walk->data.attrs.gen_i += 1; break; @@ -2266,7 +2279,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); } - if (param_type->id == ZigTypeIdPointer) { + if (type_is_nonnull_ptr(param_type)) { addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); } break; diff --git a/src/target.cpp b/src/target.cpp index 6fea79518c..b1434c6871 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -807,6 +807,10 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { zig_unreachable(); } +bool target_allows_addr_zero(const ZigTarget *target) { + return target->os == OsFreestanding; +} + const char *target_o_file_ext(ZigTarget *target) { if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) { return ".obj"; diff --git a/src/target.hpp b/src/target.hpp index a87b12351a..99d1cadf56 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -135,5 +135,6 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target ZigLLVM_OSType get_llvm_os_type(Os os_type); bool target_is_arm(const ZigTarget *target); +bool target_allows_addr_zero(const ZigTarget *target); #endif From 973a93d43b8b44d2ee8bfde09e78f8295470f337 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 18:59:20 -0500 Subject: [PATCH 196/218] add docs for C pointers --- doc/langref.html.in | 60 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 82ec13c9bb..e5a60b0bc1 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1694,7 +1694,7 @@ test "comptime @intToPtr" { } } {#code_end#} - {#see_also|Optional Pointers#} + {#see_also|Optional Pointers|@intToPtr|@ptrToInt#} {#header_open|volatile#}

Loads and stores are assumed to not have side effects. If a given load or store should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. @@ -1823,7 +1823,9 @@ fn foo(bytes: []u8) u32 { } {#code_end#} {#header_close#} + {#see_also|C Pointers#} {#header_close#} + {#header_open|Slices#} {#code_begin|test_safety|index out of bounds#} const assert = @import("std").debug.assert; @@ -3981,7 +3983,7 @@ test "implicit cast - invoke a type as a function" { {#code_end#}

Implicit casts are only allowed when it is completely unambiguous how to get from one type to another, - and the transformation is guaranteed to be safe. + and the transformation is guaranteed to be safe. There is one exception, which is {#link|C Pointers#}.

{#header_open|Implicit Cast: Stricter Qualification#}

@@ -6104,6 +6106,10 @@ test "call foo" {

Converts a pointer of one type to a pointer of another type.

+

+ {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#} + to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}. +

{#header_close#} {#header_open|@ptrToInt#} @@ -7345,10 +7351,27 @@ fn bar(f: *Foo) void { {#code_end#} {#header_close#} - {#header_open|Out of Bounds Float To Integer Cast#} + {#header_open|Out of Bounds Float to Integer Cast#}

TODO

{#header_close#} + {#header_open|Pointer Cast Invalid Null#} +

At compile-time:

+ {#code_begin|test_err|null pointer casted to type#} +comptime { + const opt_ptr: ?*i32 = null; + const ptr = @ptrCast(*i32, opt_ptr); +} + {#code_end#} +

At runtime:

+ {#code_begin|exe_err#} +pub fn main() void { + var opt_ptr: ?*i32 = null; + var ptr = @ptrCast(*i32, opt_ptr); +} + {#code_end#} + {#header_close#} + {#header_close#} {#header_open|Memory#}

TODO: explain no default allocator in zig

@@ -7439,6 +7462,7 @@ pub fn main() void { {#code_end#} {#see_also|String Literals#} {#header_close#} + {#header_open|Import from C Header File#}

The {#syntax#}@cImport{#endsyntax#} builtin function can be used @@ -7477,6 +7501,36 @@ const c = @cImport({ {#code_end#} {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#} {#header_close#} + + {#header_open|C Pointers#} +

+ This type is to be avoided whenever possible. The only valid reason for using a C pointer is in + auto-generated code from translating C code. +

+

+ When importing C header files, it is ambiguous whether pointers should be translated as + single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}). + C pointers are a compromise so that Zig code can utilize translated header files directly. +

+

{#syntax#}[*c]T{#endsyntax#} - C pointer.

+
    +
  • Supports all the syntax of the other two pointer types.
  • +
  • Implicitly casts to other pointer types, as well as {#link|Optional Pointers#}. + When a C pointer is implicitly casted to a non-optional pointer, safety-checked + {#link|Undefined Behavior#} occurs if the address is 0. +
  • +
  • Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked + {#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of + null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer + is unnecessary as one can use normal {#link|Optional Pointers#}. +
  • +
  • Supports {#link|implicit casting|Implicit Casts#} to and from integers.
  • +
  • Supports comparison with integers.
  • +
  • Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#} + please!
  • +
+ {#header_close#} + {#header_open|Exporting a C Library#}

One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages From cc7060d0d934135d797bd2bc24288ecab095051a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 19:53:46 -0500 Subject: [PATCH 197/218] compile error for C pointer with align attribute See #1059 --- src/ir.cpp | 5 +++++ test/compile_errors.zig | 12 ++++++++---- test/stage1/behavior/type_info.zig | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7c46b21717..6e190adf6f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5057,6 +5057,11 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode IrInstruction *align_value; if (align_expr != nullptr) { + if (ptr_len == PtrLenC) { + exec_add_error_node(irb->codegen, irb->exec, node, + buf_sprintf("[*c] pointers may not have align attribute")); + return irb->codegen->invalid_instruction; + } align_value = ir_gen_node(irb, align_expr, scope); if (align_value == irb->codegen->invalid_instruction) return align_value; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 5e9b691641..ab9eda3f15 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -118,13 +118,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.addTest( - "C pointer pointing to non C ABI compatible type", + "C pointer pointing to non C ABI compatible type or has align attr", \\const Foo = struct {}; - \\export fn entry() [*c]Foo { - \\ return undefined; + \\export fn a() void { + \\ const T = [*c]Foo; + \\} + \\export fn b() void { + \\ const T = [*c]align(4) u8; \\} , - ".tmp_source.zig:2:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ".tmp_source.zig:6:15: error: [*c] pointers may not have align attribute", ); cases.addTest( diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index dc185cc960..52e03c2d73 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -67,12 +67,12 @@ test "type info: C pointer type info" { } fn testCPtr() void { - const ptr_info = @typeInfo([*c]align(4) const i8); + const ptr_info = @typeInfo([*c]const i8); expect(TypeId(ptr_info) == TypeId.Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); - expect(ptr_info.Pointer.alignment == 4); + expect(ptr_info.Pointer.alignment == 1); expect(ptr_info.Pointer.child == i8); } From d5bbd748711abc82272199869cf70faf1ea30f52 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 20:04:13 -0500 Subject: [PATCH 198/218] allow C pointers to have alignment clang/gcc support pointer alignment attribute: https://clang.llvm.org/docs/AttributeReference.html#align-value --- src/ir.cpp | 5 ----- test/compile_errors.zig | 4 ---- test/stage1/behavior/type_info.zig | 4 ++-- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 6e190adf6f..7c46b21717 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5057,11 +5057,6 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode IrInstruction *align_value; if (align_expr != nullptr) { - if (ptr_len == PtrLenC) { - exec_add_error_node(irb->codegen, irb->exec, node, - buf_sprintf("[*c] pointers may not have align attribute")); - return irb->codegen->invalid_instruction; - } align_value = ir_gen_node(irb, align_expr, scope); if (align_value == irb->codegen->invalid_instruction) return align_value; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ab9eda3f15..a2fd901197 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -123,12 +123,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn a() void { \\ const T = [*c]Foo; \\} - \\export fn b() void { - \\ const T = [*c]align(4) u8; - \\} , ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", - ".tmp_source.zig:6:15: error: [*c] pointers may not have align attribute", ); cases.addTest( diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 52e03c2d73..dc185cc960 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -67,12 +67,12 @@ test "type info: C pointer type info" { } fn testCPtr() void { - const ptr_info = @typeInfo([*c]const i8); + const ptr_info = @typeInfo([*c]align(4) const i8); expect(TypeId(ptr_info) == TypeId.Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); - expect(ptr_info.Pointer.alignment == 1); + expect(ptr_info.Pointer.alignment == 4); expect(ptr_info.Pointer.child == i8); } From d6e0d82c328b4f9d733364382cce0941a601e91a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:09:12 -0500 Subject: [PATCH 199/218] translate-c: back to *c_void for opaque types See #1059 --- src/analyze.cpp | 2 +- src/ir.cpp | 13 +++++++++---- src/translate_c.cpp | 34 ++++++++++++++++++++++++++++++++-- test/compile_errors.zig | 10 ++++++++++ test/translate_c.zig | 20 ++++++++++---------- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 55deafb3a8..1917784511 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -437,7 +437,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons // move this to a parameter bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); - assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); + assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); if (byte_alignment != 0) { uint32_t abi_alignment = get_abi_alignment(g, child_type); diff --git a/src/ir.cpp b/src/ir.cpp index 7c46b21717..707eac0181 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21205,10 +21205,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); return ira->codegen->invalid_instruction; - } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { - ir_add_error(ira, &instruction->base, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_instruction; + } else if (instruction->ptr_len == PtrLenC) { + if (!type_allowed_in_extern(ira->codegen, child_type)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; + } else if (child_type->id == ZigTypeIdOpaque) { + ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); + return ira->codegen->invalid_instruction; + } } uint32_t align_bytes; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 63f04dae6c..42a7ab436d 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -763,6 +763,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { } } +static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { + switch (ty->getTypeClass()) { + case Type::Builtin: { + const BuiltinType *builtin_ty = static_cast(ty); + return builtin_ty->getKind() == BuiltinType::Void; + } + case Type::Record: { + const RecordType *record_ty = static_cast(ty); + return record_ty->getDecl()->getDefinition() == nullptr; + } + case Type::Elaborated: { + const ElaboratedType *elaborated_ty = static_cast(ty); + return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); + } + case Type::Typedef: { + const TypedefType *typedef_ty = static_cast(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); + } + default: + return false; + } +} + static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { switch (ty->getTypeClass()) { case Type::Builtin: @@ -912,8 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - return trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, PtrLenC); + if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) { + AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenSingle); + return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); + } else { + return trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenC); + } } case Type::Typedef: { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a2fd901197..1f641a9052 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "C pointer to c_void", + \\export fn a() void { + \\ var x: *c_void = undefined; + \\ var y: [*c]c_void = x; + \\} + , + ".tmp_source.zig:3:12: error: C pointers cannot point opaque types", + ); + cases.addTest( "directly embedding opaque type in struct and union", \\const O = @OpaqueType(); diff --git a/test/translate_c.zig b/test/translate_c.zig index b87b962edc..7385427dbe 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , - \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void; + \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; ); cases.add("simple struct", @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const struct_Foo = @OpaqueType(); , - \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo; + \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; , \\pub const Foo = struct_Foo; ); @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const Foo = c_void; , - \\pub extern fn fun(a: [*c]Foo) Foo; + \\pub extern fn fun(a: ?*Foo) Foo; ); cases.add("generate inline func for #define global extern fn", @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 6; \\} , - \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; \\ if ((b != 0) and (c != 0)) return 1; \\ if ((a != 0) and (c != 0)) return 2; @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return x; \\} , - \\pub export fn foo(x: [*c]c_ushort) [*c]c_void { - \\ return @ptrCast([*c]c_void, x); + \\pub export fn foo(x: [*c]c_ushort) ?*c_void { + \\ return @ptrCast(?*c_void, x); \\} ); @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !c; \\} , - \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ B, \\ C, \\}; - \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { + \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; \\ if (c != 0) return 2; @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2; @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2; From e025c70166d96d7a75a5039415321745f51f1f58 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:17:11 -0500 Subject: [PATCH 200/218] stage2: fix llvm.zig with opaque types back to single-item pointer --- src-self-hosted/llvm.zig | 20 ++++++++++---------- src-self-hosted/value.zig | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 704e83c3c6..5cb95682ab 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -11,16 +11,16 @@ const assert = @import("std").debug.assert; pub const AttributeIndex = c_uint; pub const Bool = c_int; -pub const Builder = c.LLVMBuilderRef.Child; -pub const Context = c.LLVMContextRef.Child; -pub const Module = c.LLVMModuleRef.Child; -pub const Value = c.LLVMValueRef.Child; -pub const Type = c.LLVMTypeRef.Child; -pub const BasicBlock = c.LLVMBasicBlockRef.Child; -pub const Attribute = c.LLVMAttributeRef.Child; -pub const Target = c.LLVMTargetRef.Child; -pub const TargetMachine = c.LLVMTargetMachineRef.Child; -pub const TargetData = c.LLVMTargetDataRef.Child; +pub const Builder = c.LLVMBuilderRef.Child.Child; +pub const Context = c.LLVMContextRef.Child.Child; +pub const Module = c.LLVMModuleRef.Child.Child; +pub const Value = c.LLVMValueRef.Child.Child; +pub const Type = c.LLVMTypeRef.Child.Child; +pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child; +pub const Attribute = c.LLVMAttributeRef.Child.Child; +pub const Target = c.LLVMTargetRef.Child.Child; +pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child; +pub const TargetData = c.LLVMTargetDataRef.Child.Child; pub const DIBuilder = c.ZigLLVMDIBuilder; pub const DIFile = c.ZigLLVMDIFile; pub const DICompileUnit = c.ZigLLVMDICompileUnit; diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index d9d4c3d1d9..d8c0f7b5c8 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -283,8 +283,8 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?*llvm.Value { - const llvm_type = llvm.Int1TypeInContext(ofile.context); + pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value { + const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory; if (self.x) { return llvm.ConstAllOnes(llvm_type); } else { From 18ad50970f81bd4b07892a6651487be81effc4c7 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 15 Feb 2019 17:32:13 +1300 Subject: [PATCH 201/218] Make parseFloat stricter in what it accepts as input --- std/fmt/parse_float.zig | 79 +++++++++++++++++++---------------------- std/json.zig | 2 +- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/std/fmt/parse_float.zig b/std/fmt/parse_float.zig index b83cdbbbb2..de9619efe2 100644 --- a/std/fmt/parse_float.zig +++ b/std/fmt/parse_float.zig @@ -84,10 +84,6 @@ const Z96 = struct { w += u64(d.d2) -% u64(s.d2); d.d2 = @truncate(u32, w); } - - fn dump(d: Z96) void { - std.debug.warn("{} {} {}\n", d.d0, d.d1, d.d2); - } }; const FloatRepr = struct { @@ -178,7 +174,6 @@ fn convertRepr(comptime T: type, n: FloatRepr) T { } const State = enum { - SkipLeadingWhitespace, MaybeSign, LeadingMantissaZeros, LeadingFractionalZeros, @@ -187,7 +182,6 @@ const State = enum { ExponentSign, LeadingExponentZeros, Exponent, - Stop, }; const ParseResult = enum { @@ -206,27 +200,19 @@ inline fn isSpace(c: u8) bool { return (c >= 0x09 and c <= 0x13) or c == 0x20; } -fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { +fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult { var digit_index: usize = 0; var negative = false; var negative_exp = false; var exponent: i32 = 0; - var state = State.SkipLeadingWhitespace; + var state = State.MaybeSign; var i: usize = 0; - loop: while (state != State.Stop and i < s.len) { + loop: while (i < s.len) { const c = s[i]; switch (state) { - State.SkipLeadingWhitespace => { - if (isSpace(c)) { - i += 1; - } else { - state = State.MaybeSign; - } - }, - State.MaybeSign => { state = State.LeadingMantissaZeros; @@ -238,7 +224,7 @@ fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { } else if (isDigit(c) or c == '.') { // continue } else { - state = State.Stop; + return error.InvalidCharacter; } }, @@ -329,11 +315,9 @@ fn parseRepr(s: []const u8, n: *FloatRepr) ParseResult { i += 1; } else { - state = State.Stop; + return error.InvalidCharacter; } }, - - State.Stop => break :loop, } } @@ -371,12 +355,10 @@ fn caseInEql(a: []const u8, b: []const u8) bool { return true; } -pub fn parseFloat(comptime T: type, s: []const u8) T { - var r = FloatRepr{ - .negative = false, - .exponent = 0, - .mantissa = 0, - }; +pub fn parseFloat(comptime T: type, s: []const u8) !T { + if (s.len == 0) { + return error.InvalidCharacter; + } if (caseInEql(s, "nan")) { return std.math.nan(T); @@ -386,7 +368,13 @@ pub fn parseFloat(comptime T: type, s: []const u8) T { return -std.math.inf(T); } - return switch (parseRepr(s, &r)) { + var r = FloatRepr{ + .negative = false, + .exponent = 0, + .mantissa = 0, + }; + + return switch (try parseRepr(s, &r)) { ParseResult.Ok => convertRepr(T, r), ParseResult.PlusZero => 0.0, ParseResult.MinusZero => -T(0.0), @@ -396,30 +384,37 @@ pub fn parseFloat(comptime T: type, s: []const u8) T { } test "fmt.parseFloat" { - const assert = std.debug.assert; + const testing = std.testing; + const expect = testing.expect; + const expectEqual = testing.expectEqual; const approxEq = std.math.approxEq; const epsilon = 1e-7; - inline for ([]type{ f32, f64, f128 }) |T| { + inline for ([]type{ f16, f32, f64, f128 }) |T| { const Z = @IntType(false, T.bit_count); - assert(parseFloat(T, "0") == 0.0); - assert(parseFloat(T, "+0") == 0.0); - assert(parseFloat(T, "-0") == 0.0); + testing.expectError(error.InvalidCharacter, parseFloat(T, "")); + testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); + testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc")); - assert(approxEq(T, parseFloat(T, "3.141"), 3.141, epsilon)); - assert(approxEq(T, parseFloat(T, "-3.141"), -3.141, epsilon)); + expectEqual(try parseFloat(T, "0"), 0.0); + expectEqual((try parseFloat(T, "0")), 0.0); + expectEqual((try parseFloat(T, "+0")), 0.0); + expectEqual((try parseFloat(T, "-0")), 0.0); - assert(parseFloat(T, "1e-700") == 0); - assert(parseFloat(T, "1e+700") == std.math.inf(T)); + expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon)); + expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon)); - assert(@bitCast(Z, parseFloat(T, "nAn")) == @bitCast(Z, std.math.nan(T))); - assert(parseFloat(T, "inF") == std.math.inf(T)); - assert(parseFloat(T, "-INF") == -std.math.inf(T)); + expectEqual((try parseFloat(T, "1e-700")), 0); + expectEqual((try parseFloat(T, "1e+700")), std.math.inf(T)); + + expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T))); + expectEqual((try parseFloat(T, "inF")), std.math.inf(T)); + expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T)); if (T != f16) { - assert(approxEq(T, parseFloat(T, "123142.1"), 123142.1, epsilon)); - assert(approxEq(T, parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); + expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon)); + expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon)); } } } diff --git a/std/json.zig b/std/json.zig index 5a28d9ab41..dd053e7635 100644 --- a/std/json.zig +++ b/std/json.zig @@ -1345,7 +1345,7 @@ pub const Parser = struct { return if (token.number_is_integer) Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) } else - Value{ .Float = std.fmt.parseFloat(f64, token.slice(input, i)) }; + Value{ .Float = try std.fmt.parseFloat(f64, token.slice(input, i)) }; } }; From 170ec504ec3201a89cb8121ea59e5d845f5cd1d1 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 15 Feb 2019 17:37:55 +1300 Subject: [PATCH 202/218] Use official llvm mirror for compiler-rt commit ref --- std/special/compiler_rt/addXf3.zig | 2 +- std/special/compiler_rt/addXf3_test.zig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/special/compiler_rt/addXf3.zig b/std/special/compiler_rt/addXf3.zig index 5f7f73c44f..09413b2328 100644 --- a/std/special/compiler_rt/addXf3.zig +++ b/std/special/compiler_rt/addXf3.zig @@ -1,6 +1,6 @@ // Ported from: // -// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/lib/builtins/fp_add_impl.inc +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc const std = @import("std"); const builtin = @import("builtin"); diff --git a/std/special/compiler_rt/addXf3_test.zig b/std/special/compiler_rt/addXf3_test.zig index f374a67433..099b737976 100644 --- a/std/special/compiler_rt/addXf3_test.zig +++ b/std/special/compiler_rt/addXf3_test.zig @@ -1,7 +1,7 @@ // Ported from: // -// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/test/builtins/Unit/addtf3_test.c -// https://github.com/llvm-mirror/compiler-rt/blob/92f7768ce940f6437b32ecc0985a1446cd040f7a/test/builtins/Unit/subtf3_test.c +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c +// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c const qnan128 = @bitCast(f128, u128(0x7fff800000000000) << 64); const inf128 = @bitCast(f128, u128(0x7fff000000000000) << 64); From 71d7100aa830652490d3995bf4e1319f31b5e647 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:38:14 -0500 Subject: [PATCH 203/218] darwin: fix pointer cast in mmap --- std/os/darwin.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/darwin.zig b/std/os/darwin.zig index c64ce807b6..3e883abbab 100644 --- a/std/os/darwin.zig +++ b/std/os/darwin.zig @@ -665,7 +665,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize { 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), + @ptrCast(?*c_void, address), length, @bitCast(c_int, @intCast(c_uint, prot)), @bitCast(c_int, c_uint(flags)), From 99b19adeb31469cbc4a906f036bb4d70d8730916 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:46:53 -0500 Subject: [PATCH 204/218] stage2: fix windows regressions --- src-self-hosted/libc_installation.zig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index edcb9dc579..d3a461bcd9 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -154,8 +154,8 @@ pub const LibCInstallation = struct { c.ZigFindWindowsSdkError.None => { windows_sdk = sdk; - if (sdk.msvc_lib_dir_ptr) |ptr| { - self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]); + if (sdk.msvc_lib_dir_ptr != 0) { + self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]); } try group.call(findNativeKernel32LibDir, self, loop, sdk); try group.call(findNativeIncludeDirWindows, self, loop, sdk); @@ -437,20 +437,20 @@ const Search = struct { fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { var search_end: usize = 0; - if (sdk.path10_ptr) |path10_ptr| { - if (sdk.version10_ptr) |ver10_ptr| { + if (sdk.path10_ptr != 0) { + if (sdk.version10_ptr != 0) { search_buf[search_end] = Search{ - .path = path10_ptr[0..sdk.path10_len], - .version = ver10_ptr[0..sdk.version10_len], + .path = sdk.path10_ptr[0..sdk.path10_len], + .version = sdk.version10_ptr[0..sdk.version10_len], }; search_end += 1; } } - if (sdk.path81_ptr) |path81_ptr| { - if (sdk.version81_ptr) |ver81_ptr| { + if (sdk.path81_ptr != 0) { + if (sdk.version81_ptr != 0) { search_buf[search_end] = Search{ - .path = path81_ptr[0..sdk.path81_len], - .version = ver81_ptr[0..sdk.version81_len], + .path = sdk.path81_ptr[0..sdk.path81_len], + .version = sdk.version81_ptr[0..sdk.version81_len], }; search_end += 1; } From ee5e196f8832359cfe05808677f143d4f460f6bc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Feb 2019 02:02:19 -0500 Subject: [PATCH 205/218] add test for truncate on comptime integers closes #703 --- test/stage1/behavior/truncate.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig index 568346369f..099b6c3359 100644 --- a/test/stage1/behavior/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -29,3 +29,8 @@ test "truncate sign mismatch but comptime known so it works anyway" { var result = @truncate(i8, x); expect(result == 10); } + +test "truncate on comptime integer" { + var x = @truncate(u16, 9999); + expect(x == 9999); +} From 7293e012d7956b892380517e914108ffadc6941b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Feb 2019 18:05:50 -0500 Subject: [PATCH 206/218] breaking: fix @sizeOf to be alloc size rather than store size * Fixes breaches of the guarantee that `@sizeOf(T) >= @alignOf(T)` * Fixes std.mem.secureZero for integers where this guarantee previously was breached * Fixes std.mem.Allocator for integers where this guarantee previously was breached Closes #1851 Closes #1864 --- doc/langref.html.in | 9 ++++-- src/analyze.cpp | 37 +++++++++++++++++++--- src/analyze.hpp | 1 + src/ir.cpp | 28 ++++++++++++----- std/io.zig | 13 +++----- std/mem.zig | 49 ++++++++++++------------------ test/stage1/behavior.zig | 1 + test/stage1/behavior/bugs/1851.zig | 27 ++++++++++++++++ 8 files changed, 113 insertions(+), 52 deletions(-) create mode 100644 test/stage1/behavior/bugs/1851.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index e5a60b0bc1..1341bf1be5 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6299,10 +6299,15 @@ pub const FloatMode = enum {

{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}

This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory. -

-

The result is a target-specific compile time constant.

+

+ This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset + in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#}, + consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or + {#syntax#}@typeInfo(T).Int.bits{#endsyntax#}. +

+ {#see_also|@typeInfo#} {#header_close#} {#header_open|@sliceToBytes#} diff --git a/src/analyze.cpp b/src/analyze.cpp index e2a96da7c3..7949493586 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -356,6 +356,28 @@ uint64_t type_size(CodeGen *g, ZigType *type_entry) { } } + return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref); +} + +uint64_t type_size_store(CodeGen *g, ZigType *type_entry) { + assert(type_is_complete(type_entry)); + + if (!type_has_bits(type_entry)) + return 0; + + if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } else if (type_entry->id == ZigTypeIdArray) { + ZigType *child_type = type_entry->data.array.child_type; + if (child_type->id == ZigTypeIdStruct && + child_type->data.structure.layout == ContainerLayoutPacked) + { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } + } + return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); } @@ -6230,14 +6252,19 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdStruct: { if (is_slice(type_entry)) { - ConstPtrValue *ptr = &const_val->data.x_struct.fields[slice_ptr_index].data.x_ptr; - assert(ptr->special == ConstPtrSpecialBaseArray); - ConstExprValue *array = ptr->data.base_array.array_val; - size_t start = ptr->data.base_array.elem_index; - ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; size_t len = bigint_as_unsigned(&len_val->data.x_bigint); + ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; + if (ptr_val->special == ConstValSpecialUndef) { + assert(len == 0); + buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name)); + return; + } + assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array = ptr_val->data.x_ptr.data.base_array.array_val; + size_t start = ptr_val->data.x_ptr.data.base_array.elem_index; + render_const_val_array(g, buf, &type_entry->name, array, start, len); } else { buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); diff --git a/src/analyze.hpp b/src/analyze.hpp index 845fb62534..7ded651e95 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -19,6 +19,7 @@ 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, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count); uint64_t type_size(CodeGen *g, ZigType *type_entry); +uint64_t type_size_store(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); diff --git a/src/ir.cpp b/src/ir.cpp index c9262038e0..92cdd8c891 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14331,15 +14331,15 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - size_t src_size = type_size(codegen, pointee->type); - size_t dst_size = type_size(codegen, out_val->type); - - if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { - copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - return ErrorNone; - } + // We don't need to read the padding bytes, so we look at type_size_store bytes + size_t src_size = type_size_store(codegen, pointee->type); + size_t dst_size = type_size_store(codegen, out_val->type); if (dst_size <= src_size) { + if (types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { + copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); + return ErrorNone; + } Buf buf = BUF_INIT; buf_resize(&buf, src_size); buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); @@ -15798,6 +15798,8 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, IrInstructionToPtrType *to_ptr_type_instruction) { + Error err; + IrInstruction *value = to_ptr_type_instruction->value->child; ZigType *type_entry = value->value.type; if (type_is_invalid(type_entry)) @@ -15813,7 +15815,17 @@ static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.pointer.child_type->data.array.child_type, type_entry->data.pointer.is_const); } else if (is_slice(type_entry)) { - ptr_type = adjust_ptr_len(ira->codegen, type_entry->data.structure.fields[0].type_entry, PtrLenSingle); + ZigType *slice_ptr_type = type_entry->data.structure.fields[0].type_entry; + ptr_type = adjust_ptr_len(ira->codegen, slice_ptr_type, PtrLenSingle); + // If the pointer is over-aligned, we may have to reduce it based on the alignment of the element type. + if (slice_ptr_type->data.pointer.explicit_alignment != 0) { + ZigType *elem_type = slice_ptr_type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + uint32_t elem_align = get_abi_alignment(ira->codegen, elem_type); + uint32_t reduced_align = min(elem_align, slice_ptr_type->data.pointer.explicit_alignment); + ptr_type = adjust_ptr_align(ira->codegen, ptr_type, reduced_align); + } } else if (type_entry->id == ZigTypeIdArgTuple) { ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad); if (!arg_tuple_val) diff --git a/std/io.zig b/std/io.zig index d7e8507f9b..6c70834b52 100644 --- a/std/io.zig +++ b/std/io.zig @@ -935,8 +935,6 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { }; } - - pub const BufferedAtomicFile = struct { atomic_file: os.AtomicFile, file_stream: os.File.OutStream, @@ -978,7 +976,6 @@ pub const BufferedAtomicFile = struct { } }; - pub fn readLine(buf: *std.Buffer) ![]u8 { var stdin = try getStdIn(); var stdin_stream = stdin.inStream(); @@ -1073,13 +1070,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E else => in_stream, } }; } - + pub fn alignToByte(self: *Self) void { - if(!is_packed) return; + if (!is_packed) return; self.in_stream.alignToByte(); } - //@BUG: inferred error issue. See: #1386 + //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T { comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); @@ -1088,7 +1085,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; if (is_packed) { const result = try self.in_stream.readBitsNoEof(U, t_bit_count); @@ -1301,7 +1298,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; const u_value = @bitCast(U, value); diff --git a/std/mem.zig b/std/mem.zig index 1c7523bf13..39b9701754 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. -pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { - comptime assert(T.bit_count % 8 == 0); +pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @ptrCast(*align(1) const T, bytes).*; } @@ -432,7 +431,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is foreign, so it must byte-swap. -pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { +pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @bswap(T, readIntNative(T, bytes)); } @@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) { builtin.Endian.Big => readIntNative, }; -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); + return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { @@ -481,7 +478,7 @@ pub const readIntSliceBig = switch (builtin.endian) { /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. -pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { +pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T { if (endian == builtin.endian) { return readIntNative(T, bytes); } else { @@ -489,15 +486,14 @@ pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.E } } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); + return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); } test "comptime read/write int" { @@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" { /// accepts any integer bit width. /// This function stores in native endian, which means it is implemented as a simple /// memory store. -pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void { @ptrCast(*align(1) T, buf).* = value; } @@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. /// This function stores in foreign endian, which means it does a @bswap first. -pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void { writeIntNative(T, buf, @bswap(T, value)); } @@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) { /// Writes an integer to memory, storing it in twos-complement. /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. -pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { - comptime assert(T.bit_count % 8 == 0); +pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void { if (endian == builtin.endian) { return writeIntNative(T, buffer, value); } else { @@ -575,15 +570,13 @@ pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: bui } /// Writes a twos-complement little-endian integer to memory. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer after writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntLittle /// instead. pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -595,14 +588,12 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { } /// Writes a twos-complement big-endian integer to memory. -/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buffer.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer before writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntBig instead. pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -626,7 +617,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) { }; /// Writes a twos-complement integer to memory, with the specified endianness. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be evenly divisible by 8. /// Any extra bytes in buffer not part of the integer are set to zero, with /// respect to endianness. To avoid the branch to check for extra buffer bytes, diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 1fa00b34fd..df311637fa 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -17,6 +17,7 @@ comptime { _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1486.zig"); + _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/394.zig"); _ = @import("behavior/bugs/655.zig"); _ = @import("behavior/bugs/656.zig"); diff --git a/test/stage1/behavior/bugs/1851.zig b/test/stage1/behavior/bugs/1851.zig new file mode 100644 index 0000000000..ff9ab419f8 --- /dev/null +++ b/test/stage1/behavior/bugs/1851.zig @@ -0,0 +1,27 @@ +const std = @import("std"); +const expect = std.testing.expect; + +test "allocation and looping over 3-byte integer" { + expect(@sizeOf(u24) == 4); + expect(@sizeOf([1]u24) == 4); + expect(@alignOf(u24) == 4); + expect(@alignOf([1]u24) == 4); + var buffer: [100]u8 = undefined; + const a = &std.heap.FixedBufferAllocator.init(&buffer).allocator; + + var x = a.alloc(u24, 2) catch unreachable; + expect(x.len == 2); + x[0] = 0xFFFFFF; + x[1] = 0xFFFFFF; + + const bytes = @sliceToBytes(x); + expect(@typeOf(bytes) == []align(4) u8); + expect(bytes.len == 8); + + for (bytes) |*b| { + b.* = 0x00; + } + + expect(x[0] == 0x00); + expect(x[1] == 0x00); +} From a05e224150a5a4bcad5ab1b399b43db8a0e28104 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Feb 2019 19:19:28 -0500 Subject: [PATCH 207/218] typecheck the panic function this adds the prototype of panic to @import("builtin") and then uses it to do an implicit cast of the panic function to this prototype, rather than redoing all the implicit cast logic. closes #1894 closes #1895 --- src/all_types.hpp | 1 + src/analyze.cpp | 61 +++++++++++++++-------------------------- src/analyze.hpp | 1 + src/codegen.cpp | 4 +++ src/ir.cpp | 15 ++++++---- src/ir.hpp | 2 +- test/compile_errors.zig | 14 ++++++++-- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index bafe316c3d..6fbd987b9e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1758,6 +1758,7 @@ struct CodeGen { ZigFn *cur_fn; ZigFn *main_fn; ZigFn *panic_fn; + TldFn *panic_tld_fn; AstNode *root_export_decl; CacheHash cache_hash; diff --git a/src/analyze.cpp b/src/analyze.cpp index 7949493586..12e245bd72 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1351,7 +1351,7 @@ static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *no size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr); + nullptr, nullptr, node, type_name, nullptr, nullptr); } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { @@ -3247,36 +3247,19 @@ static bool scope_is_root_decls(Scope *scope) { zig_unreachable(); } -static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) { - add_node_error(g, proto_node, - buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'", - buf_ptr(&fn_type->name))); -} +void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { + ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn"); + assert(panic_fn_type_val != nullptr); + assert(panic_fn_type_val->type->id == ZigTypeIdMetaType); + ZigType *panic_fn_type = panic_fn_type_val->data.x_type; -static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) { - AstNode *proto_node = panic_fn->proto_node; - assert(proto_node->type == NodeTypeFnProto); - ZigType *fn_type = panic_fn->type_entry; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (fn_type_id->param_count != 2) { - return wrong_panic_prototype(g, proto_node, fn_type); - } - ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0); - ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr); - if (fn_type_id->param_info[0].type != const_u8_slice) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + 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; - ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g)); - if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) { - return wrong_panic_prototype(g, proto_node, fn_type); - } - - ZigType *actual_return_type = fn_type_id->return_type; - if (actual_return_type != g->builtin_types.entry_unreachable) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + // 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); } ZigType *get_test_fn_type(CodeGen *g) { @@ -3371,18 +3354,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (!fn_table_entry->type_entry->data.fn.is_generic) { if (fn_def_node) g->fn_defs.append(fn_table_entry); + } - if (scope_is_root_decls(tld_fn->base.parent_scope) && - (import == g->root_import || import->package == g->panic_package)) + if (scope_is_root_decls(tld_fn->base.parent_scope) && + (import == g->root_import || import->package == g->panic_package)) + { + if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_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")) { - if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_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")) - { - g->panic_fn = fn_table_entry; - typecheck_panic_fn(g, fn_table_entry); - } + g->panic_fn = fn_table_entry; + g->panic_tld_fn = tld_fn; } } } else if (source_node->type == NodeTypeTestDecl) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 7ded651e95..956ef47309 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -239,4 +239,5 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *const_val, ZigType *wanted_type); +void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index d2662b10d2..d2b2836b0c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7144,6 +7144,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " instruction_addresses: []usize,\n" "};\n\n"); + buf_append_str(contents, "pub const PanicFn = fn([]const u8, ?*StackTrace) noreturn;\n\n"); + const char *cur_os = nullptr; { buf_appendf(contents, "pub const Os = enum {\n"); @@ -7913,6 +7915,8 @@ static void gen_root_source(CodeGen *g) { } } + typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); + report_errors_and_maybe_exit(g); } diff --git a/src/ir.cpp b/src/ir.cpp index 92cdd8c891..0fcbb60fe8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9949,7 +9949,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec) + IrExecutable *parent_exec, AstNode *expected_type_source_node) { if (expected_type != nullptr && type_is_invalid(expected_type)) return &codegen->invalid_instruction->value; @@ -9985,7 +9985,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod analyzed_executable->backward_branch_count = backward_branch_count; analyzed_executable->backward_branch_quota = backward_branch_quota; analyzed_executable->begin_scope = scope; - ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); + ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node); if (type_is_invalid(result_type)) return &codegen->invalid_instruction->value; @@ -10863,10 +10863,13 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } break; } + case ConstCastResultIdFnIsGeneric: + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("only one of the functions is generic")); + break; case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO - case ConstCastResultIdFnIsGeneric: // TODO case ConstCastResultIdFnReturnType: // TODO case ConstCastResultIdFnArgCount: // TODO case ConstCastResultIdFnGenericArgCount: // TODO @@ -13856,7 +13859,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call AstNode *body_node = fn_entry->body_node; result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, - nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); + nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node); if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; @@ -14052,7 +14055,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, - nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); + nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); const_instruction->base.value = *align_result; @@ -18464,7 +18467,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct ZigType *void_type = ira->codegen->builtin_types.entry_void; ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr); + &cimport_scope->buf, block_node, nullptr, nullptr, nullptr); if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; diff --git a/src/ir.hpp b/src/ir.hpp index 0a7c614812..0b85ad2c55 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec); + IrExecutable *parent_exec, AstNode *expected_type_source_node); ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, ZigType *expected_type, AstNode *expected_type_source_node); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e7108cb36a..9ef4af4162 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -346,13 +346,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "Panic declared with wrong type signature in tests", + "wrong panic signature, runtime function", \\test "" {} \\ \\pub fn panic() void {} \\ , - ".tmp_source.zig:3:5: error: expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() 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", ); cases.add( From 5736a9c6a9b357ab346dd8fcbe64f5d729d6d244 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 12 Feb 2019 10:21:45 -0600 Subject: [PATCH 208/218] removed hidden union tag in release modes --- src/analyze.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 12e245bd72..9941104bc4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2886,7 +2886,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum || enum_type_node != nullptr; bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); - bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr); + bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); ZigType *tag_type; bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); bool *covered_enum_fields; From ba56f365c813440b79c1710c6a8b0fd591883e13 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 00:42:56 -0500 Subject: [PATCH 209/218] bring zig fmt to stage1 --- CMakeLists.txt | 5 + src-self-hosted/main.zig | 6 +- src/main.cpp | 36 ++++- std/special/fmt_runner.zig | 265 +++++++++++++++++++++++++++++++++++++ 4 files changed, 305 insertions(+), 7 deletions(-) create mode 100644 std/special/fmt_runner.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e80c65dbd..db5f50908c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -652,6 +652,7 @@ set(ZIG_STD_FILES "special/compiler_rt/udivmodti4.zig" "special/compiler_rt/udivti3.zig" "special/compiler_rt/umodti3.zig" + "special/fmt_runner.zig" "special/init-exe/build.zig" "special/init-exe/src/main.zig" "special/init-lib/build.zig" @@ -905,3 +906,7 @@ foreach(file ${ZIG_STD_FILES}) get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY) install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}") endforeach() + +install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") +install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") +install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/") diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 64aa729469..42556beaed 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -24,7 +24,7 @@ var stderr_file: os.File = undefined; var stderr: *io.OutStream(os.File.WriteError) = undefined; var stdout: *io.OutStream(os.File.WriteError) = undefined; -const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB +pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB const usage = \\usage: zig [command] [options] @@ -510,7 +510,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void { return buildOutputType(allocator, args, Compilation.Kind.Obj); } -const usage_fmt = +pub const usage_fmt = \\usage: zig fmt [file]... \\ \\ Formats the input files and modifies them in-place. @@ -527,7 +527,7 @@ const usage_fmt = \\ ; -const args_fmt_spec = []Flag{ +pub const args_fmt_spec = []Flag{ Flag.Bool("--help"), Flag.Bool("--check"), Flag.Option("--color", []const []const u8{ diff --git a/src/main.cpp b/src/main.cpp index 73a1d75d42..78446f9e98 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,8 +21,8 @@ static int print_error_usage(const char *arg0) { return EXIT_FAILURE; } -static int print_full_usage(const char *arg0) { - fprintf(stdout, +static int print_full_usage(const char *arg0, FILE *file, int return_code) { + fprintf(file, "Usage: %s [command] [options]\n" "\n" "Commands:\n" @@ -31,6 +31,7 @@ static int print_full_usage(const char *arg0) { " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" " builtin show the source code of that @import(\"builtin\")\n" + " fmt parse files and render in canonical zig format\n" " help show this usage information\n" " id print the base64-encoded compiler id\n" " init-exe initialize a `zig build` application in the cwd\n" @@ -106,7 +107,7 @@ static int print_full_usage(const char *arg0) { " --test-cmd [arg] specify test execution command one arg at a time\n" " --test-cmd-bin appends test binary path to test cmd args\n" , arg0); - return EXIT_SUCCESS; + return return_code; } static const char *ZIG_ZEN = "\n" @@ -515,6 +516,31 @@ int main(int argc, char **argv) { fprintf(stderr, "\n"); } return (term.how == TerminationIdClean) ? term.code : -1; + } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) { + init_all_targets(); + 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, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(), + nullptr); + g->is_single_threaded = true; + codegen_set_out_name(g, buf_create_from_str("fmt")); + g->enable_cache = true; + + codegen_build_and_link(g); + + ZigList args = {0}; + for (int i = 2; i < argc; i += 1) { + args.append(argv[i]); + } + args.append(nullptr); + const char *exec_path = buf_ptr(&g->output_file_path); + + os_execv(exec_path, args.items); + + args.pop(); + Termination term; + os_spawn_process(exec_path, args, &term); + return term.code; } for (int i = 1; i < argc; i += 1) { @@ -527,6 +553,8 @@ int main(int argc, char **argv) { build_mode = BuildModeSafeRelease; } else if (strcmp(arg, "--release-small") == 0) { build_mode = BuildModeSmallRelease; + } else if (strcmp(arg, "--help") == 0) { + return print_full_usage(arg0, stderr, EXIT_FAILURE); } else if (strcmp(arg, "--strip") == 0) { strip = true; } else if (strcmp(arg, "--static") == 0) { @@ -1080,7 +1108,7 @@ int main(int argc, char **argv) { } } case CmdHelp: - return print_full_usage(arg0); + return print_full_usage(arg0, stdout, EXIT_SUCCESS); case CmdVersion: printf("%s\n", ZIG_VERSION_STRING); return EXIT_SUCCESS; diff --git a/std/special/fmt_runner.zig b/std/special/fmt_runner.zig new file mode 100644 index 0000000000..b6b728f5cf --- /dev/null +++ b/std/special/fmt_runner.zig @@ -0,0 +1,265 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +const os = std.os; +const io = std.io; +const mem = std.mem; +const Allocator = mem.Allocator; +const ArrayList = std.ArrayList; +const Buffer = std.Buffer; +const ast = std.zig.ast; + +const arg = @import("fmt/arg.zig"); +const self_hosted_main = @import("fmt/main.zig"); +const Args = arg.Args; +const Flag = arg.Flag; +const errmsg = @import("fmt/errmsg.zig"); + +var stderr_file: os.File = undefined; +var stderr: *io.OutStream(os.File.WriteError) = undefined; +var stdout: *io.OutStream(os.File.WriteError) = undefined; + +// This brings `zig fmt` to stage 1. +pub fn main() !void { + // Here we use an ArenaAllocator backed by a DirectAllocator because `zig fmt` is a short-lived, + // one shot program. We don't need to waste time freeing memory and finding places to squish + // bytes into. So we free everything all at once at the very end. + var direct_allocator = std.heap.DirectAllocator.init(); + var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); + const allocator = &arena.allocator; + + var stdout_file = try std.io.getStdOut(); + var stdout_out_stream = stdout_file.outStream(); + stdout = &stdout_out_stream.stream; + + stderr_file = try std.io.getStdErr(); + var stderr_out_stream = stderr_file.outStream(); + stderr = &stderr_out_stream.stream; + const args = try std.os.argsAlloc(allocator); + + var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args); + defer flags.deinit(); + + if (flags.present("help")) { + try stdout.write(self_hosted_main.usage_fmt); + os.exit(0); + } + + const color = blk: { + if (flags.single("color")) |color_flag| { + if (mem.eql(u8, color_flag, "auto")) { + break :blk errmsg.Color.Auto; + } else if (mem.eql(u8, color_flag, "on")) { + break :blk errmsg.Color.On; + } else if (mem.eql(u8, color_flag, "off")) { + break :blk errmsg.Color.Off; + } else unreachable; + } else { + break :blk errmsg.Color.Auto; + } + }; + + if (flags.present("stdin")) { + if (flags.positionals.len != 0) { + try stderr.write("cannot use --stdin with positional arguments\n"); + os.exit(1); + } + + var stdin_file = try io.getStdIn(); + var stdin = stdin_file.inStream(); + + const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size); + defer allocator.free(source_code); + + var tree = std.zig.parse(allocator, source_code) catch |err| { + try stderr.print("error parsing stdin: {}\n", err); + os.exit(1); + }; + defer tree.deinit(); + + var error_it = tree.errors.iterator(0); + while (error_it.next()) |parse_error| { + try printErrMsgToFile(allocator, parse_error, &tree, "", stderr_file, color); + } + if (tree.errors.len != 0) { + os.exit(1); + } + if (flags.present("check")) { + const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree); + const code = if (anything_changed) u8(1) else u8(0); + os.exit(code); + } + + _ = try std.zig.render(allocator, stdout, &tree); + return; + } + + if (flags.positionals.len == 0) { + try stderr.write("expected at least one source file argument\n"); + os.exit(1); + } + + if (flags.positionals.len == 0) { + try stderr.write("expected at least one source file argument\n"); + os.exit(1); + } + + var fmt = Fmt{ + .seen = Fmt.SeenMap.init(allocator), + .any_error = false, + .color = color, + .allocator = allocator, + }; + + const check_mode = flags.present("check"); + + for (flags.positionals.toSliceConst()) |file_path| { + try fmtPath(&fmt, file_path, check_mode); + } + if (fmt.any_error) { + os.exit(1); + } +} + +const FmtError = error{ + SystemResources, + OperationAborted, + IoPending, + BrokenPipe, + Unexpected, + WouldBlock, + FileClosed, + DestinationAddressRequired, + DiskQuota, + FileTooBig, + InputOutput, + NoSpaceLeft, + AccessDenied, + OutOfMemory, + RenameAcrossMountPoints, + ReadOnlyFileSystem, + LinkQuotaExceeded, + FileBusy, +} || os.File.OpenError; + +fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { + const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); + defer fmt.allocator.free(file_path); + + if (try fmt.seen.put(file_path, {})) |_| return; + + const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { + error.IsDir, error.AccessDenied => { + // TODO make event based (and dir.next()) + var dir = try std.os.Dir.open(fmt.allocator, file_path); + defer dir.close(); + + while (try dir.next()) |entry| { + if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) { + const full_path = try os.path.join(fmt.allocator, [][]const u8{ file_path, entry.name }); + try fmtPath(fmt, full_path, check_mode); + } + } + return; + }, + else => { + // TODO lock stderr printing + try stderr.print("unable to open '{}': {}\n", file_path, err); + fmt.any_error = true; + return; + }, + }; + defer fmt.allocator.free(source_code); + + var tree = std.zig.parse(fmt.allocator, source_code) catch |err| { + try stderr.print("error parsing file '{}': {}\n", file_path, err); + fmt.any_error = true; + return; + }; + defer tree.deinit(); + + var error_it = tree.errors.iterator(0); + while (error_it.next()) |parse_error| { + try printErrMsgToFile(fmt.allocator, parse_error, &tree, file_path, stderr_file, fmt.color); + } + if (tree.errors.len != 0) { + fmt.any_error = true; + return; + } + + if (check_mode) { + const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, &tree); + if (anything_changed) { + try stderr.print("{}\n", file_path); + fmt.any_error = true; + } + } else { + // TODO make this evented + const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); + defer baf.destroy(); + + const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), &tree); + if (anything_changed) { + try stderr.print("{}\n", file_path); + try baf.finish(); + } + } +} + +const Fmt = struct { + seen: SeenMap, + any_error: bool, + color: errmsg.Color, + allocator: *mem.Allocator, + + const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8); +}; + +fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, tree: *ast.Tree, + path: []const u8, file: os.File, color: errmsg.Color,) !void +{ + const color_on = switch (color) { + errmsg.Color.Auto => file.isTty(), + errmsg.Color.On => true, + errmsg.Color.Off => false, + }; + const lok_token = parse_error.loc(); + const span = errmsg.Span{ + .first = lok_token, + .last = lok_token, + }; + + const first_token = tree.tokens.at(span.first); + const last_token = tree.tokens.at(span.last); + const start_loc = tree.tokenLocationPtr(0, first_token); + const end_loc = tree.tokenLocationPtr(first_token.end, last_token); + + var text_buf = try std.Buffer.initSize(allocator, 0); + var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; + try parse_error.render(&tree.tokens, out_stream); + const text = text_buf.toOwnedSlice(); + + const stream = &file.outStream().stream; + if (!color_on) { + try stream.print( + "{}:{}:{}: error: {}\n", + path, + start_loc.line + 1, + start_loc.column + 1, + text, + ); + return; + } + + try stream.print( + "{}:{}:{}: error: {}\n{}\n", + path, + start_loc.line + 1, + start_loc.column + 1, + text, + tree.source[start_loc.line_start..start_loc.line_end], + ); + try stream.writeByteNTimes(' ', start_loc.column); + try stream.writeByteNTimes('~', last_token.end - first_token.start); + try stream.write("\n"); +} From a97362e67739c94d6266cc2d1352dd9bb1b713be Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 12:24:02 -0500 Subject: [PATCH 210/218] fmt_runner: remove redundant check --- std/special/fmt_runner.zig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/std/special/fmt_runner.zig b/std/special/fmt_runner.zig index b6b728f5cf..46ced0e136 100644 --- a/std/special/fmt_runner.zig +++ b/std/special/fmt_runner.zig @@ -99,11 +99,6 @@ pub fn main() !void { os.exit(1); } - if (flags.positionals.len == 0) { - try stderr.write("expected at least one source file argument\n"); - os.exit(1); - } - var fmt = Fmt{ .seen = Fmt.SeenMap.init(allocator), .any_error = false, From f4c5bcfea5f02dec30d7adede0550c95af424c71 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 13:34:32 -0500 Subject: [PATCH 211/218] refactor translate-c - no more using namespace clang this is in preparation for #1964 --- src/translate_c.cpp | 2276 +++++++++++++++++++++---------------------- 1 file changed, 1137 insertions(+), 1139 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 710314d1cb..7d618466b2 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -30,8 +30,6 @@ #include -using namespace clang; - struct Alias { Buf *new_name; Buf *canon_name; @@ -87,13 +85,13 @@ struct Context { HashMap decl_table; HashMap macro_table; HashMap global_table; - SourceManager *source_manager; + clang::SourceManager *source_manager; ZigList aliases; AstNode *source_node; bool warnings_on; CodeGen *codegen; - ASTContext *ctx; + clang::ASTContext *ctx; TransScopeRoot *global_scope; HashMap ptr_params; @@ -117,21 +115,21 @@ static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *paren static TransScopeBlock *trans_scope_block_find(TransScope *scope); -static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); -static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); -static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); +static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl); +static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl); +static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl); -static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, +static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt, ResultUsed result_used, TransLRValue lrval, AstNode **out_node, TransScope **out_child_scope, TransScope **out_node_scope); -static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node); -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval); -static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval); +static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node); +static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval); +static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc); +static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval); ATTRIBUTE_PRINTF(3, 4) -static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { +static void emit_warning(Context *c, const clang::SourceLocation &sl, const char *format, ...) { if (!c->warnings_on) { return; } @@ -471,8 +469,8 @@ static Buf *string_ref_to_buf(StringRef string_ref) { return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size()); } -static const char *decl_name(const Decl *decl) { - const NamedDecl *named_decl = static_cast(decl); +static const char *decl_name(const clang::Decl *decl) { + const clang::NamedDecl *named_decl = static_cast(decl); return (const char *)named_decl->getName().bytes_begin(); } @@ -490,20 +488,20 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) } -static const Type *qual_type_canon(QualType qt) { +static const clang::Type *qual_type_canon(clang::QualType qt) { return qt.getCanonicalType().getTypePtr(); } -static QualType get_expr_qual_type(Context *c, const Expr *expr) { +static clang::QualType get_expr_qual_type(Context *c, const clang::Expr *expr) { // String literals in C are `char *` but they should really be `const char *`. - if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) { - const ImplicitCastExpr *cast_expr = static_cast(expr); - if (cast_expr->getCastKind() == CK_ArrayToPointerDecay) { - const Expr *sub_expr = cast_expr->getSubExpr(); - if (sub_expr->getStmtClass() == Stmt::StringLiteralClass) { - QualType array_qt = sub_expr->getType(); - const ArrayType *array_type = static_cast(array_qt.getTypePtr()); - QualType pointee_qt = array_type->getElementType(); + if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { + const clang::ImplicitCastExpr *cast_expr = static_cast(expr); + if (cast_expr->getCastKind() == clang::CK_ArrayToPointerDecay) { + const clang::Expr *sub_expr = cast_expr->getSubExpr(); + if (sub_expr->getStmtClass() == clang::Stmt::StringLiteralClass) { + clang::QualType array_qt = sub_expr->getType(); + const clang::ArrayType *array_type = static_cast(array_qt.getTypePtr()); + clang::QualType pointee_qt = array_type->getElementType(); pointee_qt.addConst(); return c->ctx->getPointerType(pointee_qt); } @@ -512,19 +510,19 @@ static QualType get_expr_qual_type(Context *c, const Expr *expr) { return expr->getType(); } -static QualType get_expr_qual_type_before_implicit_cast(Context *c, const Expr *expr) { - if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) { - const ImplicitCastExpr *cast_expr = static_cast(expr); +static clang::QualType get_expr_qual_type_before_implicit_cast(Context *c, const clang::Expr *expr) { + if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { + const clang::ImplicitCastExpr *cast_expr = static_cast(expr); return get_expr_qual_type(c, cast_expr->getSubExpr()); } return expr->getType(); } -static AstNode *get_expr_type(Context *c, const Expr *expr) { +static AstNode *get_expr_type(Context *c, const clang::Expr *expr) { return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart()); } -static bool qual_types_equal(QualType t1, QualType t2) { +static bool qual_types_equal(clang::QualType t1, clang::QualType t2) { if (t1.isConstQualified() != t2.isConstQualified()) { return false; } @@ -541,37 +539,37 @@ static bool is_c_void_type(AstNode *node) { return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); } -static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) { - QualType t1 = get_expr_qual_type(c, expr1); - QualType t2 = get_expr_qual_type(c, expr2); +static bool expr_types_equal(Context *c, const clang::Expr *expr1, const clang::Expr *expr2) { + clang::QualType t1 = get_expr_qual_type(c, expr1); + clang::QualType t2 = get_expr_qual_type(c, expr2); return qual_types_equal(t1, t2); } -static bool qual_type_is_ptr(QualType qt) { - const Type *ty = qual_type_canon(qt); - return ty->getTypeClass() == Type::Pointer; +static bool qual_type_is_ptr(clang::QualType qt) { + const clang::Type *ty = qual_type_canon(qt); + return ty->getTypeClass() == clang::Type::Pointer; } -static const FunctionProtoType *qual_type_get_fn_proto(QualType qt, bool *is_ptr) { - const Type *ty = qual_type_canon(qt); +static const clang::FunctionProtoType *qual_type_get_fn_proto(clang::QualType qt, bool *is_ptr) { + const clang::Type *ty = qual_type_canon(qt); *is_ptr = false; - if (ty->getTypeClass() == Type::Pointer) { + if (ty->getTypeClass() == clang::Type::Pointer) { *is_ptr = true; - const PointerType *pointer_ty = static_cast(ty); - QualType child_qt = pointer_ty->getPointeeType(); + const clang::PointerType *pointer_ty = static_cast(ty); + clang::QualType child_qt = pointer_ty->getPointeeType(); ty = child_qt.getTypePtr(); } - if (ty->getTypeClass() == Type::FunctionProto) { - return static_cast(ty); + if (ty->getTypeClass() == clang::Type::FunctionProto) { + return static_cast(ty); } return nullptr; } -static bool qual_type_is_fn_ptr(QualType qt) { +static bool qual_type_is_fn_ptr(clang::QualType qt) { bool is_ptr; if (qual_type_get_fn_proto(qt, &is_ptr)) { return is_ptr; @@ -580,30 +578,30 @@ static bool qual_type_is_fn_ptr(QualType qt) { return false; } -static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { - const Type *ty = qt.getTypePtr(); +static uint32_t qual_type_int_bit_width(Context *c, const clang::QualType &qt, const clang::SourceLocation &source_loc) { + const clang::Type *ty = qt.getTypePtr(); switch (ty->getTypeClass()) { - case Type::Builtin: + case clang::Type::Builtin: { - const BuiltinType *builtin_ty = static_cast(ty); + const clang::BuiltinType *builtin_ty = static_cast(ty); switch (builtin_ty->getKind()) { - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - case BuiltinType::SChar: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: return 8; - case BuiltinType::UInt128: - case BuiltinType::Int128: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Int128: return 128; default: return 0; } zig_unreachable(); } - case Type::Typedef: + case clang::Type::Typedef: { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const clang::TypedefType *typedef_ty = static_cast(ty); + const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); const char *type_name = decl_name(typedef_decl); if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { return 8; @@ -624,8 +622,8 @@ static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const So } -static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, - const SourceLocation &source_loc) +static AstNode *qual_type_to_log2_int_ref(Context *c, const clang::QualType &qt, + const clang::SourceLocation &source_loc) { uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); if (int_bit_width != 0) { @@ -643,7 +641,7 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, // FieldAccess // FnCall (.builtin = true) // Symbol "import" -// StringLiteral "std" +// clang::StringLiteral "std" // Symbol "math" // Symbol "Log2Int" // zig_type_node @@ -657,21 +655,21 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, return log2int_fn_call; } -static bool qual_type_child_is_fn_proto(const QualType &qt) { - if (qt.getTypePtr()->getTypeClass() == Type::Paren) { - const ParenType *paren_type = static_cast(qt.getTypePtr()); - if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { +static bool qual_type_child_is_fn_proto(const clang::QualType &qt) { + if (qt.getTypePtr()->getTypeClass() == clang::Type::Paren) { + const clang::ParenType *paren_type = static_cast(qt.getTypePtr()); + if (paren_type->getInnerType()->getTypeClass() == clang::Type::FunctionProto) { return true; } - } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) { - const AttributedType *attr_type = static_cast(qt.getTypePtr()); + } else if (qt.getTypePtr()->getTypeClass() == clang::Type::Attributed) { + const clang::AttributedType *attr_type = static_cast(qt.getTypePtr()); return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); } return false; } -static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, QualType dest_type, - QualType src_type, AstNode *expr) +static AstNode* trans_c_cast(Context *c, const clang::SourceLocation &source_location, clang::QualType dest_type, + clang::QualType src_type, AstNode *expr) { if (qual_types_equal(dest_type, src_type)) { return expr; @@ -688,72 +686,72 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr); } -static bool c_is_signed_integer(Context *c, QualType qt) { - const Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != Type::Builtin) +static bool c_is_signed_integer(Context *c, clang::QualType qt) { + const clang::Type *c_type = qual_type_canon(qt); + if (c_type->getTypeClass() != clang::Type::Builtin) return false; - const BuiltinType *builtin_ty = static_cast(c_type); + const clang::BuiltinType *builtin_ty = static_cast(c_type); switch (builtin_ty->getKind()) { - case BuiltinType::SChar: - case BuiltinType::Short: - case BuiltinType::Int: - case BuiltinType::Long: - case BuiltinType::LongLong: - case BuiltinType::Int128: - case BuiltinType::WChar_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::WChar_S: return true; default: return false; } } -static bool c_is_unsigned_integer(Context *c, QualType qt) { - const Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != Type::Builtin) +static bool c_is_unsigned_integer(Context *c, clang::QualType qt) { + const clang::Type *c_type = qual_type_canon(qt); + if (c_type->getTypeClass() != clang::Type::Builtin) return false; - const BuiltinType *builtin_ty = static_cast(c_type); + const clang::BuiltinType *builtin_ty = static_cast(c_type); switch (builtin_ty->getKind()) { - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - case BuiltinType::UShort: - case BuiltinType::UInt: - case BuiltinType::ULong: - case BuiltinType::ULongLong: - case BuiltinType::UInt128: - case BuiltinType::WChar_U: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::WChar_U: return true; default: return false; } } -static bool c_is_builtin_type(Context *c, QualType qt, BuiltinType::Kind kind) { - const Type *c_type = qual_type_canon(qt); - if (c_type->getTypeClass() != Type::Builtin) +static bool c_is_builtin_type(Context *c, clang::QualType qt, clang::BuiltinType::Kind kind) { + const clang::Type *c_type = qual_type_canon(qt); + if (c_type->getTypeClass() != clang::Type::Builtin) return false; - const BuiltinType *builtin_ty = static_cast(c_type); + const clang::BuiltinType *builtin_ty = static_cast(c_type); return builtin_ty->getKind() == kind; } -static bool c_is_float(Context *c, QualType qt) { - const Type *c_type = qt.getTypePtr(); - if (c_type->getTypeClass() != Type::Builtin) +static bool c_is_float(Context *c, clang::QualType qt) { + const clang::Type *c_type = qt.getTypePtr(); + if (c_type->getTypeClass() != clang::Type::Builtin) return false; - const BuiltinType *builtin_ty = static_cast(c_type); + const clang::BuiltinType *builtin_ty = static_cast(c_type); switch (builtin_ty->getKind()) { - case BuiltinType::Half: - case BuiltinType::Float: - case BuiltinType::Double: - case BuiltinType::Float128: - case BuiltinType::LongDouble: + case clang::BuiltinType::Half: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::Float128: + case clang::BuiltinType::LongDouble: return true; default: return false; } } -static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { +static bool qual_type_has_wrapping_overflow(Context *c, clang::QualType qt) { if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { // float and signed integer overflow is undefined behavior. return false; @@ -763,23 +761,23 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { } } -static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { +static bool type_is_opaque(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) { switch (ty->getTypeClass()) { - case Type::Builtin: { - const BuiltinType *builtin_ty = static_cast(ty); - return builtin_ty->getKind() == BuiltinType::Void; + case clang::Type::Builtin: { + const clang::BuiltinType *builtin_ty = static_cast(ty); + return builtin_ty->getKind() == clang::BuiltinType::Void; } - case Type::Record: { - const RecordType *record_ty = static_cast(ty); + case clang::Type::Record: { + const clang::RecordType *record_ty = static_cast(ty); return record_ty->getDecl()->getDefinition() == nullptr; } - case Type::Elaborated: { - const ElaboratedType *elaborated_ty = static_cast(ty); + case clang::Type::Elaborated: { + const clang::ElaboratedType *elaborated_ty = static_cast(ty); return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); } - case Type::Typedef: { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + case clang::Type::Typedef: { + const clang::TypedefType *typedef_ty = static_cast(ty); + const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); } default: @@ -787,145 +785,145 @@ static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &sou } } -static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { +static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) { switch (ty->getTypeClass()) { - case Type::Builtin: + case clang::Type::Builtin: { - const BuiltinType *builtin_ty = static_cast(ty); + const clang::BuiltinType *builtin_ty = static_cast(ty); switch (builtin_ty->getKind()) { - case BuiltinType::Void: + case clang::BuiltinType::Void: return trans_create_node_symbol_str(c, "c_void"); - case BuiltinType::Bool: + case clang::BuiltinType::Bool: return trans_create_node_symbol_str(c, "bool"); - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - case BuiltinType::Char8: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::Char8: return trans_create_node_symbol_str(c, "u8"); - case BuiltinType::SChar: + case clang::BuiltinType::SChar: return trans_create_node_symbol_str(c, "i8"); - case BuiltinType::UShort: + case clang::BuiltinType::UShort: return trans_create_node_symbol_str(c, "c_ushort"); - case BuiltinType::UInt: + case clang::BuiltinType::UInt: return trans_create_node_symbol_str(c, "c_uint"); - case BuiltinType::ULong: + case clang::BuiltinType::ULong: return trans_create_node_symbol_str(c, "c_ulong"); - case BuiltinType::ULongLong: + case clang::BuiltinType::ULongLong: return trans_create_node_symbol_str(c, "c_ulonglong"); - case BuiltinType::Short: + case clang::BuiltinType::Short: return trans_create_node_symbol_str(c, "c_short"); - case BuiltinType::Int: + case clang::BuiltinType::Int: return trans_create_node_symbol_str(c, "c_int"); - case BuiltinType::Long: + case clang::BuiltinType::Long: return trans_create_node_symbol_str(c, "c_long"); - case BuiltinType::LongLong: + case clang::BuiltinType::LongLong: return trans_create_node_symbol_str(c, "c_longlong"); - case BuiltinType::UInt128: + case clang::BuiltinType::UInt128: return trans_create_node_symbol_str(c, "u128"); - case BuiltinType::Int128: + case clang::BuiltinType::Int128: return trans_create_node_symbol_str(c, "i128"); - case BuiltinType::Float: + case clang::BuiltinType::Float: return trans_create_node_symbol_str(c, "f32"); - case BuiltinType::Double: + case clang::BuiltinType::Double: return trans_create_node_symbol_str(c, "f64"); - case BuiltinType::Float128: + case clang::BuiltinType::Float128: return trans_create_node_symbol_str(c, "f128"); - case BuiltinType::Float16: + case clang::BuiltinType::Float16: return trans_create_node_symbol_str(c, "f16"); - case BuiltinType::LongDouble: + case clang::BuiltinType::LongDouble: return trans_create_node_symbol_str(c, "c_longdouble"); - case BuiltinType::WChar_U: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::WChar_S: - case BuiltinType::Half: - case BuiltinType::NullPtr: - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - case BuiltinType::OMPArraySection: - case BuiltinType::Dependent: - case BuiltinType::Overload: - case BuiltinType::BoundMember: - case BuiltinType::PseudoObject: - case BuiltinType::UnknownAny: - case BuiltinType::BuiltinFn: - case BuiltinType::ARCUnbridgedCast: - case BuiltinType::ShortAccum: - case BuiltinType::Accum: - case BuiltinType::LongAccum: - case BuiltinType::UShortAccum: - case BuiltinType::UAccum: - case BuiltinType::ULongAccum: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Half: + case clang::BuiltinType::NullPtr: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::OMPArraySection: + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::ShortAccum: + case clang::BuiltinType::Accum: + case clang::BuiltinType::LongAccum: + case clang::BuiltinType::UShortAccum: + case clang::BuiltinType::UAccum: + case clang::BuiltinType::ULongAccum: - case BuiltinType::OCLImage1dRO: - case BuiltinType::OCLImage1dArrayRO: - case BuiltinType::OCLImage1dBufferRO: - case BuiltinType::OCLImage2dRO: - case BuiltinType::OCLImage2dArrayRO: - case BuiltinType::OCLImage2dDepthRO: - case BuiltinType::OCLImage2dArrayDepthRO: - case BuiltinType::OCLImage2dMSAARO: - case BuiltinType::OCLImage2dArrayMSAARO: - case BuiltinType::OCLImage2dMSAADepthRO: - case BuiltinType::OCLImage2dArrayMSAADepthRO: - case BuiltinType::OCLImage3dRO: - case BuiltinType::OCLImage1dWO: - case BuiltinType::OCLImage1dArrayWO: - case BuiltinType::OCLImage1dBufferWO: - case BuiltinType::OCLImage2dWO: - case BuiltinType::OCLImage2dArrayWO: - case BuiltinType::OCLImage2dDepthWO: - case BuiltinType::OCLImage2dArrayDepthWO: - case BuiltinType::OCLImage2dMSAAWO: - case BuiltinType::OCLImage2dArrayMSAAWO: - case BuiltinType::OCLImage2dMSAADepthWO: - case BuiltinType::OCLImage2dArrayMSAADepthWO: - case BuiltinType::OCLImage3dWO: - case BuiltinType::OCLImage1dRW: - case BuiltinType::OCLImage1dArrayRW: - case BuiltinType::OCLImage1dBufferRW: - case BuiltinType::OCLImage2dRW: - case BuiltinType::OCLImage2dArrayRW: - case BuiltinType::OCLImage2dDepthRW: - case BuiltinType::OCLImage2dArrayDepthRW: - case BuiltinType::OCLImage2dMSAARW: - case BuiltinType::OCLImage2dArrayMSAARW: - case BuiltinType::OCLImage2dMSAADepthRW: - case BuiltinType::OCLImage2dArrayMSAADepthRW: - case BuiltinType::OCLImage3dRW: - case BuiltinType::OCLSampler: - case BuiltinType::OCLEvent: - case BuiltinType::OCLClkEvent: - case BuiltinType::OCLQueue: - case BuiltinType::OCLReserveID: - case BuiltinType::ShortFract: - case BuiltinType::Fract: - case BuiltinType::LongFract: - case BuiltinType::UShortFract: - case BuiltinType::UFract: - case BuiltinType::ULongFract: - case BuiltinType::SatShortAccum: - case BuiltinType::SatAccum: - case BuiltinType::SatLongAccum: - case BuiltinType::SatUShortAccum: - case BuiltinType::SatUAccum: - case BuiltinType::SatULongAccum: - case BuiltinType::SatShortFract: - case BuiltinType::SatFract: - case BuiltinType::SatLongFract: - case BuiltinType::SatUShortFract: - case BuiltinType::SatUFract: - case BuiltinType::SatULongFract: + case clang::BuiltinType::OCLImage1dRO: + case clang::BuiltinType::OCLImage1dArrayRO: + case clang::BuiltinType::OCLImage1dBufferRO: + case clang::BuiltinType::OCLImage2dRO: + case clang::BuiltinType::OCLImage2dArrayRO: + case clang::BuiltinType::OCLImage2dDepthRO: + case clang::BuiltinType::OCLImage2dArrayDepthRO: + case clang::BuiltinType::OCLImage2dMSAARO: + case clang::BuiltinType::OCLImage2dArrayMSAARO: + case clang::BuiltinType::OCLImage2dMSAADepthRO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: + case clang::BuiltinType::OCLImage3dRO: + case clang::BuiltinType::OCLImage1dWO: + case clang::BuiltinType::OCLImage1dArrayWO: + case clang::BuiltinType::OCLImage1dBufferWO: + case clang::BuiltinType::OCLImage2dWO: + case clang::BuiltinType::OCLImage2dArrayWO: + case clang::BuiltinType::OCLImage2dDepthWO: + case clang::BuiltinType::OCLImage2dArrayDepthWO: + case clang::BuiltinType::OCLImage2dMSAAWO: + case clang::BuiltinType::OCLImage2dArrayMSAAWO: + case clang::BuiltinType::OCLImage2dMSAADepthWO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: + case clang::BuiltinType::OCLImage3dWO: + case clang::BuiltinType::OCLImage1dRW: + case clang::BuiltinType::OCLImage1dArrayRW: + case clang::BuiltinType::OCLImage1dBufferRW: + case clang::BuiltinType::OCLImage2dRW: + case clang::BuiltinType::OCLImage2dArrayRW: + case clang::BuiltinType::OCLImage2dDepthRW: + case clang::BuiltinType::OCLImage2dArrayDepthRW: + case clang::BuiltinType::OCLImage2dMSAARW: + case clang::BuiltinType::OCLImage2dArrayMSAARW: + case clang::BuiltinType::OCLImage2dMSAADepthRW: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: + case clang::BuiltinType::OCLImage3dRW: + case clang::BuiltinType::OCLSampler: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLClkEvent: + case clang::BuiltinType::OCLQueue: + case clang::BuiltinType::OCLReserveID: + case clang::BuiltinType::ShortFract: + case clang::BuiltinType::Fract: + case clang::BuiltinType::LongFract: + case clang::BuiltinType::UShortFract: + case clang::BuiltinType::UFract: + case clang::BuiltinType::ULongFract: + case clang::BuiltinType::SatShortAccum: + case clang::BuiltinType::SatAccum: + case clang::BuiltinType::SatLongAccum: + case clang::BuiltinType::SatUShortAccum: + case clang::BuiltinType::SatUAccum: + case clang::BuiltinType::SatULongAccum: + case clang::BuiltinType::SatShortFract: + case clang::BuiltinType::SatFract: + case clang::BuiltinType::SatLongFract: + case clang::BuiltinType::SatUShortFract: + case clang::BuiltinType::SatUFract: + case clang::BuiltinType::SatULongFract: emit_warning(c, source_loc, "unsupported builtin type"); return nullptr; } break; } - case Type::Pointer: + case clang::Type::Pointer: { - const PointerType *pointer_ty = static_cast(ty); - QualType child_qt = pointer_ty->getPointeeType(); + const clang::PointerType *pointer_ty = static_cast(ty); + clang::QualType child_qt = pointer_ty->getPointeeType(); AstNode *child_node = trans_qual_type(c, child_qt, source_loc); if (child_node == nullptr) { emit_warning(c, source_loc, "pointer to unsupported type"); @@ -945,84 +943,84 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou child_qt.isVolatileQualified(), child_node, PtrLenC); } } - case Type::Typedef: + case clang::Type::Typedef: { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const clang::TypedefType *typedef_ty = static_cast(ty); + const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); return resolve_typedef_decl(c, typedef_decl); } - case Type::Elaborated: + case clang::Type::Elaborated: { - const ElaboratedType *elaborated_ty = static_cast(ty); + const clang::ElaboratedType *elaborated_ty = static_cast(ty); switch (elaborated_ty->getKeyword()) { - case ETK_Struct: - case ETK_Enum: - case ETK_Union: + case clang::ETK_Struct: + case clang::ETK_Enum: + case clang::ETK_Union: return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); - case ETK_Interface: - case ETK_Class: - case ETK_Typename: - case ETK_None: + case clang::ETK_Interface: + case clang::ETK_Class: + case clang::ETK_Typename: + case clang::ETK_None: emit_warning(c, source_loc, "unsupported elaborated type"); return nullptr; } } - case Type::FunctionProto: + case clang::Type::FunctionProto: { - const FunctionProtoType *fn_proto_ty = static_cast(ty); + const clang::FunctionProtoType *fn_proto_ty = static_cast(ty); AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); switch (fn_proto_ty->getCallConv()) { - case CC_C: // __attribute__((cdecl)) + case clang::CC_C: // __attribute__((cdecl)) proto_node->data.fn_proto.cc = CallingConventionC; proto_node->data.fn_proto.is_extern = true; break; - case CC_X86StdCall: // __attribute__((stdcall)) + case clang::CC_X86StdCall: // __attribute__((stdcall)) proto_node->data.fn_proto.cc = CallingConventionStdcall; break; - case CC_X86FastCall: // __attribute__((fastcall)) + case clang::CC_X86FastCall: // __attribute__((fastcall)) emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); return nullptr; - case CC_X86ThisCall: // __attribute__((thiscall)) + case clang::CC_X86ThisCall: // __attribute__((thiscall)) emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); return nullptr; - case CC_X86VectorCall: // __attribute__((vectorcall)) + case clang::CC_X86VectorCall: // __attribute__((vectorcall)) emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); return nullptr; - case CC_X86Pascal: // __attribute__((pascal)) + case clang::CC_X86Pascal: // __attribute__((pascal)) emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); return nullptr; - case CC_Win64: // __attribute__((ms_abi)) + case clang::CC_Win64: // __attribute__((ms_abi)) emit_warning(c, source_loc, "unsupported calling convention: win64"); return nullptr; - case CC_X86_64SysV: // __attribute__((sysv_abi)) + case clang::CC_X86_64SysV: // __attribute__((sysv_abi)) emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); return nullptr; - case CC_X86RegCall: + case clang::CC_X86RegCall: emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); return nullptr; - case CC_AAPCS: // __attribute__((pcs("aapcs"))) + case clang::CC_AAPCS: // __attribute__((pcs("aapcs"))) emit_warning(c, source_loc, "unsupported calling convention: aapcs"); return nullptr; - case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) + case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); return nullptr; - case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) + case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); return nullptr; - case CC_SpirFunction: // default for OpenCL functions on SPIR target + case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); return nullptr; - case CC_OpenCLKernel: + case clang::CC_OpenCLKernel: emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); return nullptr; - case CC_Swift: + case clang::CC_Swift: emit_warning(c, source_loc, "unsupported calling convention: Swift"); return nullptr; - case CC_PreserveMost: + case clang::CC_PreserveMost: emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); return nullptr; - case CC_PreserveAll: + case clang::CC_PreserveAll: emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); return nullptr; } @@ -1040,7 +1038,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return nullptr; } // convert c_void to actual void (only for return type) - // we do want to look at the AstNode instead of QualType, because + // we do want to look at the AstNode instead of clang::QualType, because // if they do something like: // typedef Foo void; // void foo(void) -> Foo; @@ -1057,7 +1055,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou } for (size_t i = 0; i < param_count; i += 1) { - QualType qt = fn_proto_ty->getParamType(i); + clang::QualType qt = fn_proto_ty->getParamType(i); AstNode *param_type_node = trans_qual_type(c, qt, source_loc); if (param_type_node == nullptr) { @@ -1080,19 +1078,19 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return proto_node; } - case Type::Record: + case clang::Type::Record: { - const RecordType *record_ty = static_cast(ty); + const clang::RecordType *record_ty = static_cast(ty); return resolve_record_decl(c, record_ty->getDecl()); } - case Type::Enum: + case clang::Type::Enum: { - const EnumType *enum_ty = static_cast(ty); + const clang::EnumType *enum_ty = static_cast(ty); return resolve_enum_decl(c, enum_ty->getDecl()); } - case Type::ConstantArray: + case clang::Type::ConstantArray: { - const ConstantArrayType *const_arr_ty = static_cast(ty); + const clang::ConstantArrayType *const_arr_ty = static_cast(ty); AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); if (child_type_node == nullptr) { emit_warning(c, source_loc, "unresolved array element type"); @@ -1102,25 +1100,25 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou AstNode *size_node = trans_create_node_unsigned(c, size); return trans_create_node_array_type(c, size_node, child_type_node); } - case Type::Paren: + case clang::Type::Paren: { - const ParenType *paren_ty = static_cast(ty); + const clang::ParenType *paren_ty = static_cast(ty); return trans_qual_type(c, paren_ty->getInnerType(), source_loc); } - case Type::Decayed: + case clang::Type::Decayed: { - const DecayedType *decayed_ty = static_cast(ty); + const clang::DecayedType *decayed_ty = static_cast(ty); return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); } - case Type::Attributed: + case clang::Type::Attributed: { - const AttributedType *attributed_ty = static_cast(ty); + const clang::AttributedType *attributed_ty = static_cast(ty); return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); } - case Type::IncompleteArray: + case clang::Type::IncompleteArray: { - const IncompleteArrayType *incomplete_array_ty = static_cast(ty); - QualType child_qt = incomplete_array_ty->getElementType(); + const clang::IncompleteArrayType *incomplete_array_ty = static_cast(ty); + clang::QualType child_qt = incomplete_array_ty->getElementType(); AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc); if (child_type_node == nullptr) { emit_warning(c, source_loc, "unresolved array element type"); @@ -1130,56 +1128,56 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou child_qt.isVolatileQualified(), child_type_node, PtrLenC); return pointer_node; } - case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: - case Type::MemberPointer: - case Type::VariableArray: - case Type::DependentSizedArray: - case Type::DependentSizedExtVector: - case Type::Vector: - case Type::ExtVector: - case Type::FunctionNoProto: - case Type::UnresolvedUsing: - case Type::Adjusted: - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::UnaryTransform: - case Type::TemplateTypeParm: - case Type::SubstTemplateTypeParm: - case Type::SubstTemplateTypeParmPack: - case Type::TemplateSpecialization: - case Type::Auto: - case Type::InjectedClassName: - case Type::DependentName: - case Type::DependentTemplateSpecialization: - case Type::PackExpansion: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::Complex: - case Type::ObjCObjectPointer: - case Type::Atomic: - case Type::Pipe: - case Type::ObjCTypeParam: - case Type::DeducedTemplateSpecialization: - case Type::DependentAddressSpace: - case Type::DependentVector: + case clang::Type::BlockPointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: + case clang::Type::VariableArray: + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::Vector: + case clang::Type::ExtVector: + case clang::Type::FunctionNoProto: + case clang::Type::UnresolvedUsing: + case clang::Type::Adjusted: + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + case clang::Type::UnaryTransform: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::TemplateSpecialization: + case clang::Type::Auto: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + case clang::Type::Complex: + case clang::Type::ObjCObjectPointer: + case clang::Type::Atomic: + case clang::Type::Pipe: + case clang::Type::ObjCTypeParam: + case clang::Type::DeducedTemplateSpecialization: + case clang::Type::DependentAddressSpace: + case clang::Type::DependentVector: emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); return nullptr; } zig_unreachable(); } -static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { +static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc) { return trans_type(c, qt.getTypePtr(), source_loc); } -static int trans_compound_stmt_inline(Context *c, TransScope *scope, const CompoundStmt *stmt, +static int trans_compound_stmt_inline(Context *c, TransScope *scope, const clang::CompoundStmt *stmt, AstNode *block_node, TransScope **out_node_scope) { assert(block_node->type == NodeTypeBlock); - for (CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { + for (clang::CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { AstNode *child_node; scope = trans_stmt(c, scope, *it, &child_node); if (scope == nullptr) @@ -1193,7 +1191,7 @@ static int trans_compound_stmt_inline(Context *c, TransScope *scope, const Compo return ErrorNone; } -static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const CompoundStmt *stmt, +static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const clang::CompoundStmt *stmt, TransScope **out_node_scope) { TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope); @@ -1202,8 +1200,8 @@ static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const Compoun return child_scope_block->node; } -static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStmt *stmt) { - const Expr *value_expr = stmt->getRetValue(); +static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::ReturnStmt *stmt) { + const clang::Expr *value_expr = stmt->getRetValue(); if (value_expr == nullptr) { return trans_create_node(c, NodeTypeReturnExpr); } else { @@ -1215,7 +1213,7 @@ static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStm } } -static AstNode *trans_integer_literal(Context *c, const IntegerLiteral *stmt) { +static AstNode *trans_integer_literal(Context *c, const clang::IntegerLiteral *stmt) { llvm::APSInt result; if (!stmt->EvaluateAsInt(result, *c->ctx)) { emit_warning(c, stmt->getLocStart(), "invalid integer literal"); @@ -1225,13 +1223,13 @@ static AstNode *trans_integer_literal(Context *c, const IntegerLiteral *stmt) { } static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope, - const ConditionalOperator *stmt) + const clang::ConditionalOperator *stmt) { AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); - Expr *cond_expr = stmt->getCond(); - Expr *true_expr = stmt->getTrueExpr(); - Expr *false_expr = stmt->getFalseExpr(); + clang::Expr *cond_expr = stmt->getCond(); + clang::Expr *true_expr = stmt->getTrueExpr(); + clang::Expr *false_expr = stmt->getFalseExpr(); node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue); if (node->data.if_bool_expr.condition == nullptr) @@ -1248,7 +1246,7 @@ static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, T return maybe_suppress_result(c, result_used, node); } -static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) { +static AstNode *trans_create_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) { AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = bin_op; @@ -1263,7 +1261,7 @@ static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, Bi return node; } -static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) { +static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) { assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr); AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = bin_op; @@ -1279,7 +1277,7 @@ static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lh return node; } -static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) { +static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, clang::Expr *lhs, clang::Expr *rhs) { if (result_used == ResultUsedNo) { // common case AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); @@ -1330,10 +1328,10 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco } } -static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType result_type, - Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) +static AstNode *trans_create_shift_op(Context *c, TransScope *scope, clang::QualType result_type, + clang::Expr *lhs_expr, BinOpType bin_op, clang::Expr *rhs_expr) { - const SourceLocation &rhs_location = rhs_expr->getLocStart(); + const clang::SourceLocation &rhs_location = rhs_expr->getLocStart(); AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); // lhs >> u5(rh) @@ -1347,22 +1345,22 @@ static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType re return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); } -static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const BinaryOperator *stmt) { +static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::BinaryOperator *stmt) { switch (stmt->getOpcode()) { - case BO_PtrMemD: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); + case clang::BO_PtrMemD: + emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: clang::BO_PtrMemD"); return nullptr; - case BO_PtrMemI: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); + case clang::BO_PtrMemI: + emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: clang::BO_PtrMemI"); return nullptr; - case BO_Cmp: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Cmp"); + case clang::BO_Cmp: + emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: clang::BO_Cmp"); return nullptr; - case BO_Mul: + case clang::BO_Mul: return trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, stmt->getRHS()); - case BO_Div: + case clang::BO_Div: if (qual_type_has_wrapping_overflow(c, stmt->getType())) { // unsigned/float division uses the operator return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); @@ -1377,7 +1375,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS fn_call->data.fn_call_expr.params.append(rhs); return fn_call; } - case BO_Rem: + case clang::BO_Rem: if (qual_type_has_wrapping_overflow(c, stmt->getType())) { // unsigned/float division uses the operator return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); @@ -1392,43 +1390,43 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS fn_call->data.fn_call_expr.params.append(rhs); return fn_call; } - case BO_Add: + case clang::BO_Add: return trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, stmt->getRHS()); - case BO_Sub: + case clang::BO_Sub: return trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, stmt->getRHS()); - case BO_Shl: + case clang::BO_Shl: return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); - case BO_Shr: + case clang::BO_Shr: return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); - case BO_LT: + case clang::BO_LT: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); - case BO_GT: + case clang::BO_GT: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); - case BO_LE: + case clang::BO_LE: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); - case BO_GE: + case clang::BO_GE: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); - case BO_EQ: + case clang::BO_EQ: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); - case BO_NE: + case clang::BO_NE: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); - case BO_And: + case clang::BO_And: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); - case BO_Xor: + case clang::BO_Xor: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); - case BO_Or: + case clang::BO_Or: return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); - case BO_LAnd: + case clang::BO_LAnd: return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); - case BO_LOr: + case clang::BO_LOr: return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); - case BO_Assign: + case clang::BO_Assign: return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS()); - case BO_Comma: + case clang::BO_Comma: { TransScopeBlock *scope_block = trans_scope_block_create(c, scope); Buf *label_name = buf_create_from_str("x"); @@ -1445,16 +1443,16 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs))); return scope_block->node; } - case BO_MulAssign: - case BO_DivAssign: - case BO_RemAssign: - case BO_AddAssign: - case BO_SubAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_AndAssign: - case BO_XorAssign: - case BO_OrAssign: + case clang::BO_MulAssign: + case clang::BO_DivAssign: + case clang::BO_RemAssign: + case clang::BO_AddAssign: + case clang::BO_SubAssign: + case clang::BO_ShlAssign: + case clang::BO_ShrAssign: + case clang::BO_AndAssign: + case clang::BO_XorAssign: + case clang::BO_OrAssign: zig_unreachable(); } @@ -1462,9 +1460,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS } static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope, - const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) + const clang::CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { - const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); + const clang::SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); @@ -1544,7 +1542,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result } static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, TransScope *scope, - const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) + const clang::CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { if (result_used == ResultUsedNo) { // simple common case, where the C and Zig are identical: @@ -1604,76 +1602,76 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_used, TransScope *scope, - const CompoundAssignOperator *stmt) + const clang::CompoundAssignOperator *stmt) { switch (stmt->getOpcode()) { - case BO_MulAssign: + case clang::BO_MulAssign: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult); - case BO_DivAssign: - emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); + case clang::BO_DivAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: clang::BO_DivAssign"); return nullptr; - case BO_RemAssign: - emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); + case clang::BO_RemAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: clang::BO_RemAssign"); return nullptr; - case BO_Cmp: - emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_Cmp"); + case clang::BO_Cmp: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: clang::BO_Cmp"); return nullptr; - case BO_AddAssign: + case clang::BO_AddAssign: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); - case BO_SubAssign: + case clang::BO_SubAssign: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); else return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub); - case BO_ShlAssign: + case clang::BO_ShlAssign: return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); - case BO_ShrAssign: + case clang::BO_ShrAssign: return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); - case BO_AndAssign: + case clang::BO_AndAssign: return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); - case BO_XorAssign: + case clang::BO_XorAssign: return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); - case BO_OrAssign: + case clang::BO_OrAssign: return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); - case BO_PtrMemD: - case BO_PtrMemI: - case BO_Assign: - case BO_Mul: - case BO_Div: - case BO_Rem: - case BO_Add: - case BO_Sub: - case BO_Shl: - case BO_Shr: - case BO_LT: - case BO_GT: - case BO_LE: - case BO_GE: - case BO_EQ: - case BO_NE: - case BO_And: - case BO_Xor: - case BO_Or: - case BO_LAnd: - case BO_LOr: - case BO_Comma: + case clang::BO_PtrMemD: + case clang::BO_PtrMemI: + case clang::BO_Assign: + case clang::BO_Mul: + case clang::BO_Div: + case clang::BO_Rem: + case clang::BO_Add: + case clang::BO_Sub: + case clang::BO_Shl: + case clang::BO_Shr: + case clang::BO_LT: + case clang::BO_GT: + case clang::BO_LE: + case clang::BO_GE: + case clang::BO_EQ: + case clang::BO_NE: + case clang::BO_And: + case clang::BO_Xor: + case clang::BO_Or: + case clang::BO_LAnd: + case clang::BO_LOr: + case clang::BO_Comma: zig_unreachable(); } zig_unreachable(); } -static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const ImplicitCastExpr *stmt) { +static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const clang::ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { - case CK_LValueToRValue: + case clang::CK_LValueToRValue: return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); - case CK_IntegralCast: + case clang::CK_IntegralCast: { AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) @@ -1681,15 +1679,15 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), stmt->getSubExpr()->getType(), target_node); } - case CK_FunctionToPointerDecay: - case CK_ArrayToPointerDecay: + case clang::CK_FunctionToPointerDecay: + case clang::CK_ArrayToPointerDecay: { AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) return nullptr; return target_node; } - case CK_BitCast: + case clang::CK_BitCast: { AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) @@ -1706,170 +1704,170 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im node->data.fn_call_expr.params.append(target_node); return node; } - case CK_NullToPointer: + case clang::CK_NullToPointer: return trans_create_node_unsigned(c, 0); - case CK_Dependent: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); + case clang::CK_Dependent: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_Dependent"); return nullptr; - case CK_LValueBitCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); + case clang::CK_LValueBitCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_LValueBitCast"); return nullptr; - case CK_NoOp: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NoOp"); + case clang::CK_NoOp: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_NoOp"); return nullptr; - case CK_BaseToDerived: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerived"); + case clang::CK_BaseToDerived: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_BaseToDerived"); return nullptr; - case CK_DerivedToBase: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBase"); + case clang::CK_DerivedToBase: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_DerivedToBase"); return nullptr; - case CK_UncheckedDerivedToBase: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); + case clang::CK_UncheckedDerivedToBase: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_UncheckedDerivedToBase"); return nullptr; - case CK_Dynamic: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dynamic"); + case clang::CK_Dynamic: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_Dynamic"); return nullptr; - case CK_ToUnion: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); + case clang::CK_ToUnion: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ToUnion"); return nullptr; - case CK_NullToMemberPointer: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); + case clang::CK_NullToMemberPointer: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_NullToMemberPointer"); return nullptr; - case CK_BaseToDerivedMemberPointer: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); + case clang::CK_BaseToDerivedMemberPointer: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_BaseToDerivedMemberPointer"); return nullptr; - case CK_DerivedToBaseMemberPointer: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); + case clang::CK_DerivedToBaseMemberPointer: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_DerivedToBaseMemberPointer"); return nullptr; - case CK_MemberPointerToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_MemberPointerToBoolean"); + case clang::CK_MemberPointerToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_MemberPointerToBoolean"); return nullptr; - case CK_ReinterpretMemberPointer: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); + case clang::CK_ReinterpretMemberPointer: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ReinterpretMemberPointer"); return nullptr; - case CK_UserDefinedConversion: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UserDefinedConversion"); + case clang::CK_UserDefinedConversion: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_UserDefinedConversion"); return nullptr; - case CK_ConstructorConversion: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ConstructorConversion"); + case clang::CK_ConstructorConversion: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ConstructorConversion"); return nullptr; - case CK_IntegralToPointer: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToPointer"); + case clang::CK_IntegralToPointer: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralToPointer"); return nullptr; - case CK_PointerToIntegral: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToIntegral"); + case clang::CK_PointerToIntegral: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_PointerToIntegral"); return nullptr; - case CK_PointerToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToBoolean"); + case clang::CK_PointerToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_PointerToBoolean"); return nullptr; - case CK_ToVoid: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToVoid"); + case clang::CK_ToVoid: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ToVoid"); return nullptr; - case CK_VectorSplat: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_VectorSplat"); + case clang::CK_VectorSplat: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_VectorSplat"); return nullptr; - case CK_IntegralToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToBoolean"); + case clang::CK_IntegralToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralToBoolean"); return nullptr; - case CK_IntegralToFloating: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToFloating"); + case clang::CK_IntegralToFloating: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralToFloating"); return nullptr; - case CK_FloatingToIntegral: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToIntegral"); + case clang::CK_FloatingToIntegral: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingToIntegral"); return nullptr; - case CK_FloatingToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToBoolean"); + case clang::CK_FloatingToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingToBoolean"); return nullptr; - case CK_BooleanToSignedIntegral: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BooleanToSignedIntegral"); + case clang::CK_BooleanToSignedIntegral: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_BooleanToSignedIntegral"); return nullptr; - case CK_FloatingCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingCast"); + case clang::CK_FloatingCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingCast"); return nullptr; - case CK_CPointerToObjCPointerCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CPointerToObjCPointerCast"); + case clang::CK_CPointerToObjCPointerCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_CPointerToObjCPointerCast"); return nullptr; - case CK_BlockPointerToObjCPointerCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); + case clang::CK_BlockPointerToObjCPointerCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_BlockPointerToObjCPointerCast"); return nullptr; - case CK_AnyPointerToBlockPointerCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); + case clang::CK_AnyPointerToBlockPointerCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_AnyPointerToBlockPointerCast"); return nullptr; - case CK_ObjCObjectLValueCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ObjCObjectLValueCast"); + case clang::CK_ObjCObjectLValueCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ObjCObjectLValueCast"); return nullptr; - case CK_FloatingRealToComplex: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingRealToComplex"); + case clang::CK_FloatingRealToComplex: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingRealToComplex"); return nullptr; - case CK_FloatingComplexToReal: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToReal"); + case clang::CK_FloatingComplexToReal: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingComplexToReal"); return nullptr; - case CK_FloatingComplexToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToBoolean"); + case clang::CK_FloatingComplexToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingComplexToBoolean"); return nullptr; - case CK_FloatingComplexCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexCast"); + case clang::CK_FloatingComplexCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingComplexCast"); return nullptr; - case CK_FloatingComplexToIntegralComplex: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); + case clang::CK_FloatingComplexToIntegralComplex: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_FloatingComplexToIntegralComplex"); return nullptr; - case CK_IntegralRealToComplex: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralRealToComplex"); + case clang::CK_IntegralRealToComplex: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralRealToComplex"); return nullptr; - case CK_IntegralComplexToReal: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToReal"); + case clang::CK_IntegralComplexToReal: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralComplexToReal"); return nullptr; - case CK_IntegralComplexToBoolean: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToBoolean"); + case clang::CK_IntegralComplexToBoolean: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralComplexToBoolean"); return nullptr; - case CK_IntegralComplexCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexCast"); + case clang::CK_IntegralComplexCast: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralComplexCast"); return nullptr; - case CK_IntegralComplexToFloatingComplex: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); + case clang::CK_IntegralComplexToFloatingComplex: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntegralComplexToFloatingComplex"); return nullptr; - case CK_ARCProduceObject: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCProduceObject"); + case clang::CK_ARCProduceObject: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ARCProduceObject"); return nullptr; - case CK_ARCConsumeObject: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCConsumeObject"); + case clang::CK_ARCConsumeObject: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ARCConsumeObject"); return nullptr; - case CK_ARCReclaimReturnedObject: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCReclaimReturnedObject"); + case clang::CK_ARCReclaimReturnedObject: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ARCReclaimReturnedObject"); return nullptr; - case CK_ARCExtendBlockObject: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCExtendBlockObject"); + case clang::CK_ARCExtendBlockObject: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ARCExtendBlockObject"); return nullptr; - case CK_AtomicToNonAtomic: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AtomicToNonAtomic"); + case clang::CK_AtomicToNonAtomic: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_AtomicToNonAtomic"); return nullptr; - case CK_NonAtomicToAtomic: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NonAtomicToAtomic"); + case clang::CK_NonAtomicToAtomic: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_NonAtomicToAtomic"); return nullptr; - case CK_CopyAndAutoreleaseBlockObject: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); + case clang::CK_CopyAndAutoreleaseBlockObject: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_CopyAndAutoreleaseBlockObject"); return nullptr; - case CK_BuiltinFnToFnPtr: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BuiltinFnToFnPtr"); + case clang::CK_BuiltinFnToFnPtr: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_BuiltinFnToFnPtr"); return nullptr; - case CK_ZeroToOCLEvent: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLEvent"); + case clang::CK_ZeroToOCLEvent: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ZeroToOCLEvent"); return nullptr; - case CK_ZeroToOCLQueue: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLQueue"); + case clang::CK_ZeroToOCLQueue: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_ZeroToOCLQueue"); return nullptr; - case CK_AddressSpaceConversion: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AddressSpaceConversion"); + case clang::CK_AddressSpaceConversion: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_AddressSpaceConversion"); return nullptr; - case CK_IntToOCLSampler: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntToOCLSampler"); + case clang::CK_IntToOCLSampler: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast clang::CK_IntToOCLSampler"); return nullptr; } zig_unreachable(); } -static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRefExpr *stmt, TransLRValue lrval) { - const ValueDecl *value_decl = stmt->getDecl(); +static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const clang::DeclRefExpr *stmt, TransLRValue lrval) { + const clang::ValueDecl *value_decl = stmt->getDecl(); Buf *c_symbol_name = buf_create_from_str(decl_name(value_decl)); Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name); if (lrval == TransLValue) { @@ -1879,9 +1877,9 @@ static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRef } static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope, - const UnaryOperator *stmt, BinOpType assign_op) + const clang::UnaryOperator *stmt, BinOpType assign_op) { - Expr *op_expr = stmt->getSubExpr(); + clang::Expr *op_expr = stmt->getSubExpr(); if (result_used == ResultUsedNo) { // common case @@ -1935,9 +1933,9 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr } static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope, - const UnaryOperator *stmt, BinOpType assign_op) + const clang::UnaryOperator *stmt, BinOpType assign_op) { - Expr *op_expr = stmt->getSubExpr(); + clang::Expr *op_expr = stmt->getSubExpr(); if (result_used == ResultUsedNo) { // common case @@ -1984,36 +1982,36 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra return child_scope->node; } -static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const UnaryOperator *stmt) { +static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryOperator *stmt) { switch (stmt->getOpcode()) { - case UO_PostInc: + case clang::UO_PostInc: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); else return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); - case UO_PostDec: + case clang::UO_PostDec: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); else return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); - case UO_PreInc: + case clang::UO_PreInc: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); else return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); - case UO_PreDec: + case clang::UO_PreDec: if (qual_type_has_wrapping_overflow(c, stmt->getType())) return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); else return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); - case UO_AddrOf: + case clang::UO_AddrOf: { AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue); if (value_node == nullptr) return value_node; return trans_create_node_addr_of(c, value_node); } - case UO_Deref: + case clang::UO_Deref: { AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue); if (value_node == nullptr) @@ -2024,12 +2022,12 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node); return trans_create_node_ptr_deref(c, unwrapped); } - case UO_Plus: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); + case clang::UO_Plus: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Plus"); return nullptr; - case UO_Minus: + case clang::UO_Minus: { - Expr *op_expr = stmt->getSubExpr(); + clang::Expr *op_expr = stmt->getSubExpr(); if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = PrefixOpNegation; @@ -2055,41 +2053,41 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc return nullptr; } } - case UO_Not: + case clang::UO_Not: { - Expr *op_expr = stmt->getSubExpr(); + clang::Expr *op_expr = stmt->getSubExpr(); AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); if (sub_node == nullptr) return nullptr; return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); } - case UO_LNot: + case clang::UO_LNot: { - Expr *op_expr = stmt->getSubExpr(); + clang::Expr *op_expr = stmt->getSubExpr(); AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue); if (sub_node == nullptr) return nullptr; return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); } - case UO_Real: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); + case clang::UO_Real: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Real"); return nullptr; - case UO_Imag: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Imag"); + case clang::UO_Imag: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Imag"); return nullptr; - case UO_Extension: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Extension"); + case clang::UO_Extension: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Extension"); return nullptr; - case UO_Coawait: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Coawait"); + case clang::UO_Coawait: + emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Coawait"); return nullptr; } zig_unreachable(); } -static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt *stmt, +static int trans_local_declaration(Context *c, TransScope *scope, const clang::DeclStmt *stmt, AstNode **out_node, TransScope **out_scope) { // declarations are added via the scope @@ -2099,11 +2097,11 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt assert(scope_block != nullptr); for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { - Decl *decl = *iter; + clang::Decl *decl = *iter; switch (decl->getKind()) { - case Decl::Var: { - VarDecl *var_decl = (VarDecl *)decl; - QualType qual_type = var_decl->getTypeSourceInfo()->getType(); + case clang::Decl::Var: { + clang::VarDecl *var_decl = (clang::VarDecl *)decl; + clang::QualType qual_type = var_decl->getTypeSourceInfo()->getType(); AstNode *init_node = nullptr; if (var_decl->hasInit()) { init_node = trans_expr(c, ResultUsedYes, scope, var_decl->getInit(), TransRValue); @@ -2128,220 +2126,220 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt scope_block->node->data.block.statements.append(node); continue; } - case Decl::AccessSpec: + case clang::Decl::AccessSpec: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec"); return ErrorUnexpected; - case Decl::Block: + case clang::Decl::Block: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block"); return ErrorUnexpected; - case Decl::Captured: + case clang::Decl::Captured: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured"); return ErrorUnexpected; - case Decl::ClassScopeFunctionSpecialization: + case clang::Decl::ClassScopeFunctionSpecialization: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization"); return ErrorUnexpected; - case Decl::Empty: + case clang::Decl::Empty: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty"); return ErrorUnexpected; - case Decl::Export: + case clang::Decl::Export: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export"); return ErrorUnexpected; - case Decl::ExternCContext: + case clang::Decl::ExternCContext: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext"); return ErrorUnexpected; - case Decl::FileScopeAsm: + case clang::Decl::FileScopeAsm: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm"); return ErrorUnexpected; - case Decl::Friend: + case clang::Decl::Friend: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend"); return ErrorUnexpected; - case Decl::FriendTemplate: + case clang::Decl::FriendTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate"); return ErrorUnexpected; - case Decl::Import: + case clang::Decl::Import: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import"); return ErrorUnexpected; - case Decl::LinkageSpec: + case clang::Decl::LinkageSpec: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec"); return ErrorUnexpected; - case Decl::Label: + case clang::Decl::Label: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label"); return ErrorUnexpected; - case Decl::Namespace: + case clang::Decl::Namespace: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace"); return ErrorUnexpected; - case Decl::NamespaceAlias: + case clang::Decl::NamespaceAlias: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias"); return ErrorUnexpected; - case Decl::ObjCCompatibleAlias: + case clang::Decl::ObjCCompatibleAlias: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias"); return ErrorUnexpected; - case Decl::ObjCCategory: + case clang::Decl::ObjCCategory: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory"); return ErrorUnexpected; - case Decl::ObjCCategoryImpl: + case clang::Decl::ObjCCategoryImpl: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl"); return ErrorUnexpected; - case Decl::ObjCImplementation: + case clang::Decl::ObjCImplementation: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation"); return ErrorUnexpected; - case Decl::ObjCInterface: + case clang::Decl::ObjCInterface: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface"); return ErrorUnexpected; - case Decl::ObjCProtocol: + case clang::Decl::ObjCProtocol: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol"); return ErrorUnexpected; - case Decl::ObjCMethod: + case clang::Decl::ObjCMethod: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod"); return ErrorUnexpected; - case Decl::ObjCProperty: + case clang::Decl::ObjCProperty: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty"); return ErrorUnexpected; - case Decl::BuiltinTemplate: + case clang::Decl::BuiltinTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate"); return ErrorUnexpected; - case Decl::ClassTemplate: + case clang::Decl::ClassTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate"); return ErrorUnexpected; - case Decl::FunctionTemplate: + case clang::Decl::FunctionTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate"); return ErrorUnexpected; - case Decl::TypeAliasTemplate: + case clang::Decl::TypeAliasTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate"); return ErrorUnexpected; - case Decl::VarTemplate: + case clang::Decl::VarTemplate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate"); return ErrorUnexpected; - case Decl::TemplateTemplateParm: + case clang::Decl::TemplateTemplateParm: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm"); return ErrorUnexpected; - case Decl::Enum: + case clang::Decl::Enum: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum"); return ErrorUnexpected; - case Decl::Record: + case clang::Decl::Record: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record"); return ErrorUnexpected; - case Decl::CXXRecord: + case clang::Decl::CXXRecord: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord"); return ErrorUnexpected; - case Decl::ClassTemplateSpecialization: + case clang::Decl::ClassTemplateSpecialization: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization"); return ErrorUnexpected; - case Decl::ClassTemplatePartialSpecialization: + case clang::Decl::ClassTemplatePartialSpecialization: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization"); return ErrorUnexpected; - case Decl::TemplateTypeParm: + case clang::Decl::TemplateTypeParm: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm"); return ErrorUnexpected; - case Decl::ObjCTypeParam: + case clang::Decl::ObjCTypeParam: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam"); return ErrorUnexpected; - case Decl::TypeAlias: + case clang::Decl::TypeAlias: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias"); return ErrorUnexpected; - case Decl::Typedef: + case clang::Decl::Typedef: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef"); return ErrorUnexpected; - case Decl::UnresolvedUsingTypename: + case clang::Decl::UnresolvedUsingTypename: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename"); return ErrorUnexpected; - case Decl::Using: + case clang::Decl::Using: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using"); return ErrorUnexpected; - case Decl::UsingDirective: + case clang::Decl::UsingDirective: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective"); return ErrorUnexpected; - case Decl::UsingPack: + case clang::Decl::UsingPack: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack"); return ErrorUnexpected; - case Decl::UsingShadow: + case clang::Decl::UsingShadow: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow"); return ErrorUnexpected; - case Decl::ConstructorUsingShadow: + case clang::Decl::ConstructorUsingShadow: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow"); return ErrorUnexpected; - case Decl::Binding: + case clang::Decl::Binding: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding"); return ErrorUnexpected; - case Decl::Field: + case clang::Decl::Field: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field"); return ErrorUnexpected; - case Decl::ObjCAtDefsField: + case clang::Decl::ObjCAtDefsField: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField"); return ErrorUnexpected; - case Decl::ObjCIvar: + case clang::Decl::ObjCIvar: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar"); return ErrorUnexpected; - case Decl::Function: + case clang::Decl::Function: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function"); return ErrorUnexpected; - case Decl::CXXDeductionGuide: + case clang::Decl::CXXDeductionGuide: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide"); return ErrorUnexpected; - case Decl::CXXMethod: + case clang::Decl::CXXMethod: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod"); return ErrorUnexpected; - case Decl::CXXConstructor: + case clang::Decl::CXXConstructor: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor"); return ErrorUnexpected; - case Decl::CXXConversion: + case clang::Decl::CXXConversion: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion"); return ErrorUnexpected; - case Decl::CXXDestructor: + case clang::Decl::CXXDestructor: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor"); return ErrorUnexpected; - case Decl::MSProperty: + case clang::Decl::MSProperty: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty"); return ErrorUnexpected; - case Decl::NonTypeTemplateParm: + case clang::Decl::NonTypeTemplateParm: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm"); return ErrorUnexpected; - case Decl::Decomposition: + case clang::Decl::Decomposition: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition"); return ErrorUnexpected; - case Decl::ImplicitParam: + case clang::Decl::ImplicitParam: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam"); return ErrorUnexpected; - case Decl::OMPCapturedExpr: + case clang::Decl::OMPCapturedExpr: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr"); return ErrorUnexpected; - case Decl::ParmVar: + case clang::Decl::ParmVar: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar"); return ErrorUnexpected; - case Decl::VarTemplateSpecialization: + case clang::Decl::VarTemplateSpecialization: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization"); return ErrorUnexpected; - case Decl::VarTemplatePartialSpecialization: + case clang::Decl::VarTemplatePartialSpecialization: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization"); return ErrorUnexpected; - case Decl::EnumConstant: + case clang::Decl::EnumConstant: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant"); return ErrorUnexpected; - case Decl::IndirectField: + case clang::Decl::IndirectField: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField"); return ErrorUnexpected; - case Decl::OMPDeclareReduction: + case clang::Decl::OMPDeclareReduction: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction"); return ErrorUnexpected; - case Decl::UnresolvedUsingValue: + case clang::Decl::UnresolvedUsingValue: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue"); return ErrorUnexpected; - case Decl::OMPThreadPrivate: + case clang::Decl::OMPThreadPrivate: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate"); return ErrorUnexpected; - case Decl::ObjCPropertyImpl: + case clang::Decl::ObjCPropertyImpl: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl"); return ErrorUnexpected; - case Decl::PragmaComment: + case clang::Decl::PragmaComment: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment"); return ErrorUnexpected; - case Decl::PragmaDetectMismatch: + case clang::Decl::PragmaDetectMismatch: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch"); return ErrorUnexpected; - case Decl::StaticAssert: + case clang::Decl::StaticAssert: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert"); return ErrorUnexpected; - case Decl::TranslationUnit: + case clang::Decl::TranslationUnit: emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit"); return ErrorUnexpected; } @@ -2368,7 +2366,7 @@ static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type) return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast); } -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval) { +static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval) { AstNode *res = trans_expr(c, result_used, scope, expr, lrval); if (res == nullptr) return nullptr; @@ -2405,133 +2403,133 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * } - const Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr(); + const clang::Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr(); auto classs = ty->getTypeClass(); switch (classs) { - case Type::Builtin: + case clang::Type::Builtin: { - const BuiltinType *builtin_ty = static_cast(ty); + const clang::BuiltinType *builtin_ty = static_cast(ty); switch (builtin_ty->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - case BuiltinType::SChar: - case BuiltinType::UShort: - case BuiltinType::UInt: - case BuiltinType::ULong: - case BuiltinType::ULongLong: - case BuiltinType::Short: - case BuiltinType::Int: - case BuiltinType::Long: - case BuiltinType::LongLong: - case BuiltinType::UInt128: - case BuiltinType::Int128: - case BuiltinType::Float: - case BuiltinType::Double: - case BuiltinType::Float128: - case BuiltinType::LongDouble: - case BuiltinType::WChar_U: - case BuiltinType::Char8: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::WChar_S: - case BuiltinType::Float16: + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::Int128: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::Float128: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::WChar_U: + case clang::BuiltinType::Char8: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Float16: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); - case BuiltinType::NullPtr: + case clang::BuiltinType::NullPtr: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned(c, 0)); - case BuiltinType::Void: - case BuiltinType::Half: - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - case BuiltinType::OMPArraySection: - case BuiltinType::Dependent: - case BuiltinType::Overload: - case BuiltinType::BoundMember: - case BuiltinType::PseudoObject: - case BuiltinType::UnknownAny: - case BuiltinType::BuiltinFn: - case BuiltinType::ARCUnbridgedCast: - case BuiltinType::OCLImage1dRO: - case BuiltinType::OCLImage1dArrayRO: - case BuiltinType::OCLImage1dBufferRO: - case BuiltinType::OCLImage2dRO: - case BuiltinType::OCLImage2dArrayRO: - case BuiltinType::OCLImage2dDepthRO: - case BuiltinType::OCLImage2dArrayDepthRO: - case BuiltinType::OCLImage2dMSAARO: - case BuiltinType::OCLImage2dArrayMSAARO: - case BuiltinType::OCLImage2dMSAADepthRO: - case BuiltinType::OCLImage2dArrayMSAADepthRO: - case BuiltinType::OCLImage3dRO: - case BuiltinType::OCLImage1dWO: - case BuiltinType::OCLImage1dArrayWO: - case BuiltinType::OCLImage1dBufferWO: - case BuiltinType::OCLImage2dWO: - case BuiltinType::OCLImage2dArrayWO: - case BuiltinType::OCLImage2dDepthWO: - case BuiltinType::OCLImage2dArrayDepthWO: - case BuiltinType::OCLImage2dMSAAWO: - case BuiltinType::OCLImage2dArrayMSAAWO: - case BuiltinType::OCLImage2dMSAADepthWO: - case BuiltinType::OCLImage2dArrayMSAADepthWO: - case BuiltinType::OCLImage3dWO: - case BuiltinType::OCLImage1dRW: - case BuiltinType::OCLImage1dArrayRW: - case BuiltinType::OCLImage1dBufferRW: - case BuiltinType::OCLImage2dRW: - case BuiltinType::OCLImage2dArrayRW: - case BuiltinType::OCLImage2dDepthRW: - case BuiltinType::OCLImage2dArrayDepthRW: - case BuiltinType::OCLImage2dMSAARW: - case BuiltinType::OCLImage2dArrayMSAARW: - case BuiltinType::OCLImage2dMSAADepthRW: - case BuiltinType::OCLImage2dArrayMSAADepthRW: - case BuiltinType::OCLImage3dRW: - case BuiltinType::OCLSampler: - case BuiltinType::OCLEvent: - case BuiltinType::OCLClkEvent: - case BuiltinType::OCLQueue: - case BuiltinType::OCLReserveID: - case BuiltinType::ShortAccum: - case BuiltinType::Accum: - case BuiltinType::LongAccum: - case BuiltinType::UShortAccum: - case BuiltinType::UAccum: - case BuiltinType::ULongAccum: - case BuiltinType::ShortFract: - case BuiltinType::Fract: - case BuiltinType::LongFract: - case BuiltinType::UShortFract: - case BuiltinType::UFract: - case BuiltinType::ULongFract: - case BuiltinType::SatShortAccum: - case BuiltinType::SatAccum: - case BuiltinType::SatLongAccum: - case BuiltinType::SatUShortAccum: - case BuiltinType::SatUAccum: - case BuiltinType::SatULongAccum: - case BuiltinType::SatShortFract: - case BuiltinType::SatFract: - case BuiltinType::SatLongFract: - case BuiltinType::SatUShortFract: - case BuiltinType::SatUFract: - case BuiltinType::SatULongFract: + case clang::BuiltinType::Void: + case clang::BuiltinType::Half: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::OMPArraySection: + case clang::BuiltinType::Dependent: + case clang::BuiltinType::Overload: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::UnknownAny: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::OCLImage1dRO: + case clang::BuiltinType::OCLImage1dArrayRO: + case clang::BuiltinType::OCLImage1dBufferRO: + case clang::BuiltinType::OCLImage2dRO: + case clang::BuiltinType::OCLImage2dArrayRO: + case clang::BuiltinType::OCLImage2dDepthRO: + case clang::BuiltinType::OCLImage2dArrayDepthRO: + case clang::BuiltinType::OCLImage2dMSAARO: + case clang::BuiltinType::OCLImage2dArrayMSAARO: + case clang::BuiltinType::OCLImage2dMSAADepthRO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRO: + case clang::BuiltinType::OCLImage3dRO: + case clang::BuiltinType::OCLImage1dWO: + case clang::BuiltinType::OCLImage1dArrayWO: + case clang::BuiltinType::OCLImage1dBufferWO: + case clang::BuiltinType::OCLImage2dWO: + case clang::BuiltinType::OCLImage2dArrayWO: + case clang::BuiltinType::OCLImage2dDepthWO: + case clang::BuiltinType::OCLImage2dArrayDepthWO: + case clang::BuiltinType::OCLImage2dMSAAWO: + case clang::BuiltinType::OCLImage2dArrayMSAAWO: + case clang::BuiltinType::OCLImage2dMSAADepthWO: + case clang::BuiltinType::OCLImage2dArrayMSAADepthWO: + case clang::BuiltinType::OCLImage3dWO: + case clang::BuiltinType::OCLImage1dRW: + case clang::BuiltinType::OCLImage1dArrayRW: + case clang::BuiltinType::OCLImage1dBufferRW: + case clang::BuiltinType::OCLImage2dRW: + case clang::BuiltinType::OCLImage2dArrayRW: + case clang::BuiltinType::OCLImage2dDepthRW: + case clang::BuiltinType::OCLImage2dArrayDepthRW: + case clang::BuiltinType::OCLImage2dMSAARW: + case clang::BuiltinType::OCLImage2dArrayMSAARW: + case clang::BuiltinType::OCLImage2dMSAADepthRW: + case clang::BuiltinType::OCLImage2dArrayMSAADepthRW: + case clang::BuiltinType::OCLImage3dRW: + case clang::BuiltinType::OCLSampler: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLClkEvent: + case clang::BuiltinType::OCLQueue: + case clang::BuiltinType::OCLReserveID: + case clang::BuiltinType::ShortAccum: + case clang::BuiltinType::Accum: + case clang::BuiltinType::LongAccum: + case clang::BuiltinType::UShortAccum: + case clang::BuiltinType::UAccum: + case clang::BuiltinType::ULongAccum: + case clang::BuiltinType::ShortFract: + case clang::BuiltinType::Fract: + case clang::BuiltinType::LongFract: + case clang::BuiltinType::UShortFract: + case clang::BuiltinType::UFract: + case clang::BuiltinType::ULongFract: + case clang::BuiltinType::SatShortAccum: + case clang::BuiltinType::SatAccum: + case clang::BuiltinType::SatLongAccum: + case clang::BuiltinType::SatUShortAccum: + case clang::BuiltinType::SatUAccum: + case clang::BuiltinType::SatULongAccum: + case clang::BuiltinType::SatShortFract: + case clang::BuiltinType::SatFract: + case clang::BuiltinType::SatLongFract: + case clang::BuiltinType::SatUShortFract: + case clang::BuiltinType::SatUFract: + case clang::BuiltinType::SatULongFract: return res; } break; } - case Type::Pointer: + case clang::Type::Pointer: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned(c, 0)); - case Type::Typedef: + case clang::Type::Typedef: { - const TypedefType *typedef_ty = static_cast(ty); - const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const clang::TypedefType *typedef_ty = static_cast(ty); + const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; @@ -2540,79 +2538,79 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * return res; } - case Type::Enum: + case clang::Type::Enum: { - const EnumType *enum_ty = static_cast(ty); + const clang::EnumType *enum_ty = static_cast(ty); AstNode *enum_type = resolve_enum_decl(c, enum_ty->getDecl()); return to_enum_zero_cmp(c, res, enum_type); } - case Type::Elaborated: + case clang::Type::Elaborated: { - const ElaboratedType *elaborated_ty = static_cast(ty); + const clang::ElaboratedType *elaborated_ty = static_cast(ty); switch (elaborated_ty->getKeyword()) { - case ETK_Enum: { + case clang::ETK_Enum: { AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getLocStart()); return to_enum_zero_cmp(c, res, enum_type); } - case ETK_Struct: - case ETK_Union: - case ETK_Interface: - case ETK_Class: - case ETK_Typename: - case ETK_None: + case clang::ETK_Struct: + case clang::ETK_Union: + case clang::ETK_Interface: + case clang::ETK_Class: + case clang::ETK_Typename: + case clang::ETK_None: return res; } } - case Type::FunctionProto: - case Type::Record: - case Type::ConstantArray: - case Type::Paren: - case Type::Decayed: - case Type::Attributed: - case Type::IncompleteArray: - case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: - case Type::MemberPointer: - case Type::VariableArray: - case Type::DependentSizedArray: - case Type::DependentSizedExtVector: - case Type::Vector: - case Type::ExtVector: - case Type::FunctionNoProto: - case Type::UnresolvedUsing: - case Type::Adjusted: - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::UnaryTransform: - case Type::TemplateTypeParm: - case Type::SubstTemplateTypeParm: - case Type::SubstTemplateTypeParmPack: - case Type::TemplateSpecialization: - case Type::Auto: - case Type::InjectedClassName: - case Type::DependentName: - case Type::DependentTemplateSpecialization: - case Type::PackExpansion: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::Complex: - case Type::ObjCObjectPointer: - case Type::Atomic: - case Type::Pipe: - case Type::ObjCTypeParam: - case Type::DeducedTemplateSpecialization: - case Type::DependentAddressSpace: - case Type::DependentVector: + case clang::Type::FunctionProto: + case clang::Type::Record: + case clang::Type::ConstantArray: + case clang::Type::Paren: + case clang::Type::Decayed: + case clang::Type::Attributed: + case clang::Type::IncompleteArray: + case clang::Type::BlockPointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: + case clang::Type::VariableArray: + case clang::Type::DependentSizedArray: + case clang::Type::DependentSizedExtVector: + case clang::Type::Vector: + case clang::Type::ExtVector: + case clang::Type::FunctionNoProto: + case clang::Type::UnresolvedUsing: + case clang::Type::Adjusted: + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + case clang::Type::UnaryTransform: + case clang::Type::TemplateTypeParm: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::SubstTemplateTypeParmPack: + case clang::Type::TemplateSpecialization: + case clang::Type::Auto: + case clang::Type::InjectedClassName: + case clang::Type::DependentName: + case clang::Type::DependentTemplateSpecialization: + case clang::Type::PackExpansion: + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + case clang::Type::Complex: + case clang::Type::ObjCObjectPointer: + case clang::Type::Atomic: + case clang::Type::Pipe: + case clang::Type::ObjCTypeParam: + case clang::Type::DeducedTemplateSpecialization: + case clang::Type::DependentAddressSpace: + case clang::Type::DependentVector: return res; } zig_unreachable(); } -static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) { +static AstNode *trans_while_loop(Context *c, TransScope *scope, const clang::WhileStmt *stmt) { TransScopeWhile *while_scope = trans_scope_while_create(c, scope); while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); @@ -2627,7 +2625,7 @@ static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt return while_scope->node; } -static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) { +static AstNode *trans_if_statement(Context *c, TransScope *scope, const clang::IfStmt *stmt) { // if (c) t // if (c) t else e AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); @@ -2649,7 +2647,7 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt * return if_node; } -static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) { +static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::CallExpr *stmt) { AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, stmt->getCallee(), TransRValue); @@ -2657,16 +2655,16 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * return nullptr; bool is_ptr = false; - const FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr); + const clang::FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr); AstNode *callee_node = nullptr; if (is_ptr && fn_ty) { - if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) { - const ImplicitCastExpr *implicit_cast = static_cast(stmt->getCallee()); - if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) { - if (implicit_cast->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) { - const DeclRefExpr *decl_ref = static_cast(implicit_cast->getSubExpr()); - const Decl *decl = decl_ref->getFoundDecl(); - if (decl->getKind() == Decl::Function) { + if (stmt->getCallee()->getStmtClass() == clang::Stmt::ImplicitCastExprClass) { + const clang::ImplicitCastExpr *implicit_cast = static_cast(stmt->getCallee()); + if (implicit_cast->getCastKind() == clang::CK_FunctionToPointerDecay) { + if (implicit_cast->getSubExpr()->getStmtClass() == clang::Stmt::DeclRefExprClass) { + const clang::DeclRefExpr *decl_ref = static_cast(implicit_cast->getSubExpr()); + const clang::Decl *decl = decl_ref->getFoundDecl(); + if (decl->getKind() == clang::Decl::Function) { callee_node = callee_raw_node; } } @@ -2682,7 +2680,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * node->data.fn_call_expr.fn_ref_expr = callee_node; unsigned num_args = stmt->getNumArgs(); - const Expr * const* args = stmt->getArgs(); + const clang::Expr * const* args = stmt->getArgs(); for (unsigned i = 0; i < num_args; i += 1) { AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue); if (arg_node == nullptr) @@ -2698,7 +2696,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * return node; } -static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExpr *stmt) { +static AstNode *trans_member_expr(Context *c, TransScope *scope, const clang::MemberExpr *stmt) { AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); if (container_node == nullptr) return nullptr; @@ -2713,7 +2711,7 @@ static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExp return node; } -static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const ArraySubscriptExpr *stmt) { +static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const clang::ArraySubscriptExpr *stmt) { AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); if (container_node == nullptr) return nullptr; @@ -2730,7 +2728,7 @@ static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const } static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, - const CStyleCastExpr *stmt, TransLRValue lrvalue) + const clang::CStyleCastExpr *stmt, TransLRValue lrvalue) { AstNode *sub_expr_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), lrvalue); if (sub_expr_node == nullptr) @@ -2740,7 +2738,7 @@ static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, Tran } static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope, - const UnaryExprOrTypeTraitExpr *stmt) + const clang::UnaryExprOrTypeTraitExpr *stmt) { AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); if (type_node == nullptr) @@ -2751,14 +2749,14 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scop return node; } -static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt *stmt) { +static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang::DoStmt *stmt) { TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope); while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); AstNode *body_node; TransScope *child_scope; - if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { + if (stmt->getBody()->getStmtClass() == clang::Stmt::CompoundStmtClass) { // there's already a block in C, so we'll append our condition to it. // c: do { // c: a; @@ -2811,11 +2809,11 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt return while_scope->node; } -static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) { +static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const clang::ForStmt *stmt) { AstNode *loop_block_node; TransScopeWhile *while_scope; TransScope *cond_scope; - const Stmt *init_stmt = stmt->getInit(); + const clang::Stmt *init_stmt = stmt->getInit(); if (init_stmt == nullptr) { while_scope = trans_scope_while_create(c, parent_scope); loop_block_node = while_scope->node; @@ -2836,12 +2834,12 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt child_scope->node->data.block.statements.append(while_scope->node); } - const Stmt *cond_stmt = stmt->getCond(); + const clang::Stmt *cond_stmt = stmt->getCond(); if (cond_stmt == nullptr) { while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); } else { - if (Expr::classof(cond_stmt)) { - const Expr *cond_expr = static_cast(cond_stmt); + if (clang::Expr::classof(cond_stmt)) { + const clang::Expr *cond_expr = static_cast(cond_stmt); while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, cond_expr, TransRValue); if (while_scope->node->data.while_expr.condition == nullptr) @@ -2854,7 +2852,7 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt } } - const Stmt *inc_stmt = stmt->getInc(); + const clang::Stmt *inc_stmt = stmt->getInc(); if (inc_stmt != nullptr) { AstNode *inc_node; TransScope *inc_scope = trans_stmt(c, cond_scope, inc_stmt, &inc_node); @@ -2877,12 +2875,12 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt return loop_block_node; } -static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) { +static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const clang::SwitchStmt *stmt) { TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope); TransScopeSwitch *switch_scope; - const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt(); + const clang::DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt(); if (var_decl_stmt == nullptr) { switch_scope = trans_scope_switch_create(c, &block_scope->base); } else { @@ -2901,7 +2899,7 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw switch_scope->end_label_name = end_label_name; block_scope->node->data.block.name = end_label_name; - const Expr *cond_expr = stmt->getCond(); + const clang::Expr *cond_expr = stmt->getCond(); assert(cond_expr != nullptr); AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); @@ -2910,9 +2908,9 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw switch_scope->switch_node->data.switch_expr.expr = expr_node; AstNode *body_node; - const Stmt *body_stmt = stmt->getBody(); - if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) { - if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt, + const clang::Stmt *body_stmt = stmt->getBody(); + if (body_stmt->getStmtClass() == clang::Stmt::CompoundStmtClass) { + if (trans_compound_stmt_inline(c, &switch_scope->base, (const clang::CompoundStmt *)body_stmt, block_scope->node, nullptr)) { return nullptr; @@ -2944,7 +2942,7 @@ static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) { return nullptr; } -static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node, +static int trans_switch_case(Context *c, TransScope *parent_scope, const clang::CaseStmt *stmt, AstNode **out_node, TransScope **out_scope) { *out_node = nullptr; @@ -2989,7 +2987,7 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStm return ErrorNone; } -static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node, +static int trans_switch_default(Context *c, TransScope *parent_scope, const clang::DefaultStmt *stmt, AstNode **out_node, TransScope **out_scope) { *out_node = nullptr; @@ -3026,25 +3024,25 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const Defa return ErrorNone; } -static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) { +static AstNode *trans_string_literal(Context *c, TransScope *scope, const clang::StringLiteral *stmt) { switch (stmt->getKind()) { - case StringLiteral::Ascii: - case StringLiteral::UTF8: + case clang::StringLiteral::Ascii: + case clang::StringLiteral::UTF8: return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString())); - case StringLiteral::UTF16: + case clang::StringLiteral::UTF16: emit_warning(c, stmt->getLocStart(), "TODO support UTF16 string literals"); return nullptr; - case StringLiteral::UTF32: + case clang::StringLiteral::UTF32: emit_warning(c, stmt->getLocStart(), "TODO support UTF32 string literals"); return nullptr; - case StringLiteral::Wide: + case clang::StringLiteral::Wide: emit_warning(c, stmt->getLocStart(), "TODO support wide string literals"); return nullptr; } zig_unreachable(); } -static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) { +static AstNode *trans_break_stmt(Context *c, TransScope *scope, const clang::BreakStmt *stmt) { TransScope *cur_scope = scope; while (cur_scope != nullptr) { if (cur_scope->id == TransScopeIdWhile) { @@ -3058,7 +3056,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt zig_unreachable(); } -static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) { +static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const clang::ContinueStmt *stmt) { return trans_create_node(c, NodeTypeContinue); } @@ -3071,47 +3069,47 @@ static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_ return ErrorNone; } -static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, +static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt, ResultUsed result_used, TransLRValue lrvalue, AstNode **out_node, TransScope **out_child_scope, TransScope **out_node_scope) { - Stmt::StmtClass sc = stmt->getStmtClass(); + clang::Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { - case Stmt::ReturnStmtClass: + case clang::Stmt::ReturnStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_return_stmt(c, scope, (const ReturnStmt *)stmt)); - case Stmt::CompoundStmtClass: + trans_return_stmt(c, scope, (const clang::ReturnStmt *)stmt)); + case clang::Stmt::CompoundStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_compound_stmt(c, scope, (const CompoundStmt *)stmt, out_node_scope)); - case Stmt::IntegerLiteralClass: + trans_compound_stmt(c, scope, (const clang::CompoundStmt *)stmt, out_node_scope)); + case clang::Stmt::IntegerLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_integer_literal(c, (const IntegerLiteral *)stmt)); - case Stmt::ConditionalOperatorClass: + trans_integer_literal(c, (const clang::IntegerLiteral *)stmt)); + case clang::Stmt::ConditionalOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_conditional_operator(c, result_used, scope, (const ConditionalOperator *)stmt)); - case Stmt::BinaryOperatorClass: + trans_conditional_operator(c, result_used, scope, (const clang::ConditionalOperator *)stmt)); + case clang::Stmt::BinaryOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_binary_operator(c, result_used, scope, (const BinaryOperator *)stmt)); - case Stmt::CompoundAssignOperatorClass: + trans_binary_operator(c, result_used, scope, (const clang::BinaryOperator *)stmt)); + case clang::Stmt::CompoundAssignOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_compound_assign_operator(c, result_used, scope, (const CompoundAssignOperator *)stmt)); - case Stmt::ImplicitCastExprClass: + trans_compound_assign_operator(c, result_used, scope, (const clang::CompoundAssignOperator *)stmt)); + case clang::Stmt::ImplicitCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_implicit_cast_expr(c, scope, (const ImplicitCastExpr *)stmt)); - case Stmt::DeclRefExprClass: + trans_implicit_cast_expr(c, scope, (const clang::ImplicitCastExpr *)stmt)); + case clang::Stmt::DeclRefExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_decl_ref_expr(c, scope, (const DeclRefExpr *)stmt, lrvalue)); - case Stmt::UnaryOperatorClass: + trans_decl_ref_expr(c, scope, (const clang::DeclRefExpr *)stmt, lrvalue)); + case clang::Stmt::UnaryOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt)); - case Stmt::DeclStmtClass: - return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope); - case Stmt::DoStmtClass: - case Stmt::WhileStmtClass: { - AstNode *while_node = sc == Stmt::DoStmtClass - ? trans_do_loop(c, scope, (const DoStmt *)stmt) - : trans_while_loop(c, scope, (const WhileStmt *)stmt); + trans_unary_operator(c, result_used, scope, (const clang::UnaryOperator *)stmt)); + case clang::Stmt::DeclStmtClass: + return trans_local_declaration(c, scope, (const clang::DeclStmt *)stmt, out_node, out_child_scope); + case clang::Stmt::DoStmtClass: + case clang::Stmt::WhileStmtClass: { + AstNode *while_node = sc == clang::Stmt::DoStmtClass + ? trans_do_loop(c, scope, (const clang::DoStmt *)stmt) + : trans_while_loop(c, scope, (const clang::WhileStmt *)stmt); if (while_node == nullptr) return ErrorUnexpected; @@ -3122,556 +3120,556 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, return wrap_stmt(out_node, out_child_scope, scope, while_node); } - case Stmt::IfStmtClass: + case clang::Stmt::IfStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_if_statement(c, scope, (const IfStmt *)stmt)); - case Stmt::CallExprClass: + trans_if_statement(c, scope, (const clang::IfStmt *)stmt)); + case clang::Stmt::CallExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_call_expr(c, result_used, scope, (const CallExpr *)stmt)); - case Stmt::NullStmtClass: + trans_call_expr(c, result_used, scope, (const clang::CallExpr *)stmt)); + case clang::Stmt::NullStmtClass: *out_node = nullptr; *out_child_scope = scope; return ErrorNone; - case Stmt::MemberExprClass: + case clang::Stmt::MemberExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_member_expr(c, scope, (const MemberExpr *)stmt)); - case Stmt::ArraySubscriptExprClass: + trans_member_expr(c, scope, (const clang::MemberExpr *)stmt)); + case clang::Stmt::ArraySubscriptExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_array_subscript_expr(c, scope, (const ArraySubscriptExpr *)stmt)); - case Stmt::CStyleCastExprClass: + trans_array_subscript_expr(c, scope, (const clang::ArraySubscriptExpr *)stmt)); + case clang::Stmt::CStyleCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_c_style_cast_expr(c, result_used, scope, (const CStyleCastExpr *)stmt, lrvalue)); - case Stmt::UnaryExprOrTypeTraitExprClass: + trans_c_style_cast_expr(c, result_used, scope, (const clang::CStyleCastExpr *)stmt, lrvalue)); + case clang::Stmt::UnaryExprOrTypeTraitExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt)); - case Stmt::ForStmtClass: { - AstNode *node = trans_for_loop(c, scope, (const ForStmt *)stmt); + trans_unary_expr_or_type_trait_expr(c, scope, (const clang::UnaryExprOrTypeTraitExpr *)stmt)); + case clang::Stmt::ForStmtClass: { + AstNode *node = trans_for_loop(c, scope, (const clang::ForStmt *)stmt); return wrap_stmt(out_node, out_child_scope, scope, node); } - case Stmt::StringLiteralClass: + case clang::Stmt::StringLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_string_literal(c, scope, (const StringLiteral *)stmt)); - case Stmt::BreakStmtClass: + trans_string_literal(c, scope, (const clang::StringLiteral *)stmt)); + case clang::Stmt::BreakStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_break_stmt(c, scope, (const BreakStmt *)stmt)); - case Stmt::ContinueStmtClass: + trans_break_stmt(c, scope, (const clang::BreakStmt *)stmt)); + case clang::Stmt::ContinueStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_continue_stmt(c, scope, (const ContinueStmt *)stmt)); - case Stmt::ParenExprClass: + trans_continue_stmt(c, scope, (const clang::ContinueStmt *)stmt)); + case clang::Stmt::ParenExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); - case Stmt::SwitchStmtClass: + trans_expr(c, result_used, scope, ((const clang::ParenExpr*)stmt)->getSubExpr(), lrvalue)); + case clang::Stmt::SwitchStmtClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_switch_stmt(c, scope, (const SwitchStmt *)stmt)); - case Stmt::CaseStmtClass: - return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope); - case Stmt::DefaultStmtClass: - return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope); - case Stmt::NoStmtClass: + trans_switch_stmt(c, scope, (const clang::SwitchStmt *)stmt)); + case clang::Stmt::CaseStmtClass: + return trans_switch_case(c, scope, (const clang::CaseStmt *)stmt, out_node, out_child_scope); + case clang::Stmt::DefaultStmtClass: + return trans_switch_default(c, scope, (const clang::DefaultStmt *)stmt, out_node, out_child_scope); + case clang::Stmt::NoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); return ErrorUnexpected; - case Stmt::GCCAsmStmtClass: + case clang::Stmt::GCCAsmStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass"); return ErrorUnexpected; - case Stmt::MSAsmStmtClass: + case clang::Stmt::MSAsmStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass"); return ErrorUnexpected; - case Stmt::AttributedStmtClass: + case clang::Stmt::AttributedStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass"); return ErrorUnexpected; - case Stmt::CXXCatchStmtClass: + case clang::Stmt::CXXCatchStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass"); return ErrorUnexpected; - case Stmt::CXXForRangeStmtClass: + case clang::Stmt::CXXForRangeStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass"); return ErrorUnexpected; - case Stmt::CXXTryStmtClass: + case clang::Stmt::CXXTryStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass"); return ErrorUnexpected; - case Stmt::CapturedStmtClass: + case clang::Stmt::CapturedStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass"); return ErrorUnexpected; - case Stmt::CoreturnStmtClass: + case clang::Stmt::CoreturnStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass"); return ErrorUnexpected; - case Stmt::CoroutineBodyStmtClass: + case clang::Stmt::CoroutineBodyStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); return ErrorUnexpected; - case Stmt::BinaryConditionalOperatorClass: + case clang::Stmt::BinaryConditionalOperatorClass: emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); return ErrorUnexpected; - case Stmt::AddrLabelExprClass: + case clang::Stmt::AddrLabelExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass"); return ErrorUnexpected; - case Stmt::ArrayInitIndexExprClass: + case clang::Stmt::ArrayInitIndexExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass"); return ErrorUnexpected; - case Stmt::ArrayInitLoopExprClass: + case clang::Stmt::ArrayInitLoopExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); return ErrorUnexpected; - case Stmt::ArrayTypeTraitExprClass: + case clang::Stmt::ArrayTypeTraitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); return ErrorUnexpected; - case Stmt::AsTypeExprClass: + case clang::Stmt::AsTypeExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass"); return ErrorUnexpected; - case Stmt::AtomicExprClass: + case clang::Stmt::AtomicExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); return ErrorUnexpected; - case Stmt::BlockExprClass: + case clang::Stmt::BlockExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); return ErrorUnexpected; - case Stmt::CXXBindTemporaryExprClass: + case clang::Stmt::CXXBindTemporaryExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass"); return ErrorUnexpected; - case Stmt::CXXBoolLiteralExprClass: + case clang::Stmt::CXXBoolLiteralExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass"); return ErrorUnexpected; - case Stmt::CXXConstructExprClass: + case clang::Stmt::CXXConstructExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass"); return ErrorUnexpected; - case Stmt::CXXTemporaryObjectExprClass: + case clang::Stmt::CXXTemporaryObjectExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass"); return ErrorUnexpected; - case Stmt::CXXDefaultArgExprClass: + case clang::Stmt::CXXDefaultArgExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass"); return ErrorUnexpected; - case Stmt::CXXDefaultInitExprClass: + case clang::Stmt::CXXDefaultInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass"); return ErrorUnexpected; - case Stmt::CXXDeleteExprClass: + case clang::Stmt::CXXDeleteExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass"); return ErrorUnexpected; - case Stmt::CXXDependentScopeMemberExprClass: + case clang::Stmt::CXXDependentScopeMemberExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass"); return ErrorUnexpected; - case Stmt::CXXFoldExprClass: + case clang::Stmt::CXXFoldExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass"); return ErrorUnexpected; - case Stmt::CXXInheritedCtorInitExprClass: + case clang::Stmt::CXXInheritedCtorInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass"); return ErrorUnexpected; - case Stmt::CXXNewExprClass: + case clang::Stmt::CXXNewExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass"); return ErrorUnexpected; - case Stmt::CXXNoexceptExprClass: + case clang::Stmt::CXXNoexceptExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass"); return ErrorUnexpected; - case Stmt::CXXNullPtrLiteralExprClass: + case clang::Stmt::CXXNullPtrLiteralExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass"); return ErrorUnexpected; - case Stmt::CXXPseudoDestructorExprClass: + case clang::Stmt::CXXPseudoDestructorExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass"); return ErrorUnexpected; - case Stmt::CXXScalarValueInitExprClass: + case clang::Stmt::CXXScalarValueInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass"); return ErrorUnexpected; - case Stmt::CXXStdInitializerListExprClass: + case clang::Stmt::CXXStdInitializerListExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass"); return ErrorUnexpected; - case Stmt::CXXThisExprClass: + case clang::Stmt::CXXThisExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass"); return ErrorUnexpected; - case Stmt::CXXThrowExprClass: + case clang::Stmt::CXXThrowExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass"); return ErrorUnexpected; - case Stmt::CXXTypeidExprClass: + case clang::Stmt::CXXTypeidExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass"); return ErrorUnexpected; - case Stmt::CXXUnresolvedConstructExprClass: + case clang::Stmt::CXXUnresolvedConstructExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass"); return ErrorUnexpected; - case Stmt::CXXUuidofExprClass: + case clang::Stmt::CXXUuidofExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); return ErrorUnexpected; - case Stmt::CUDAKernelCallExprClass: + case clang::Stmt::CUDAKernelCallExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); return ErrorUnexpected; - case Stmt::CXXMemberCallExprClass: + case clang::Stmt::CXXMemberCallExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); return ErrorUnexpected; - case Stmt::CXXOperatorCallExprClass: + case clang::Stmt::CXXOperatorCallExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass"); return ErrorUnexpected; - case Stmt::UserDefinedLiteralClass: + case clang::Stmt::UserDefinedLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); return ErrorUnexpected; - case Stmt::CXXFunctionalCastExprClass: + case clang::Stmt::CXXFunctionalCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); return ErrorUnexpected; - case Stmt::CXXConstCastExprClass: + case clang::Stmt::CXXConstCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass"); return ErrorUnexpected; - case Stmt::CXXDynamicCastExprClass: + case clang::Stmt::CXXDynamicCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass"); return ErrorUnexpected; - case Stmt::CXXReinterpretCastExprClass: + case clang::Stmt::CXXReinterpretCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass"); return ErrorUnexpected; - case Stmt::CXXStaticCastExprClass: + case clang::Stmt::CXXStaticCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass"); return ErrorUnexpected; - case Stmt::ObjCBridgedCastExprClass: + case clang::Stmt::ObjCBridgedCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass"); return ErrorUnexpected; - case Stmt::CharacterLiteralClass: + case clang::Stmt::CharacterLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass"); return ErrorUnexpected; - case Stmt::ChooseExprClass: + case clang::Stmt::ChooseExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass"); return ErrorUnexpected; - case Stmt::CompoundLiteralExprClass: + case clang::Stmt::CompoundLiteralExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass"); return ErrorUnexpected; - case Stmt::ConvertVectorExprClass: + case clang::Stmt::ConvertVectorExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass"); return ErrorUnexpected; - case Stmt::CoawaitExprClass: + case clang::Stmt::CoawaitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass"); return ErrorUnexpected; - case Stmt::CoyieldExprClass: + case clang::Stmt::CoyieldExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass"); return ErrorUnexpected; - case Stmt::DependentCoawaitExprClass: + case clang::Stmt::DependentCoawaitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass"); return ErrorUnexpected; - case Stmt::DependentScopeDeclRefExprClass: + case clang::Stmt::DependentScopeDeclRefExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass"); return ErrorUnexpected; - case Stmt::DesignatedInitExprClass: + case clang::Stmt::DesignatedInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass"); return ErrorUnexpected; - case Stmt::DesignatedInitUpdateExprClass: + case clang::Stmt::DesignatedInitUpdateExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass"); return ErrorUnexpected; - case Stmt::ExprWithCleanupsClass: + case clang::Stmt::ExprWithCleanupsClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass"); return ErrorUnexpected; - case Stmt::ExpressionTraitExprClass: + case clang::Stmt::ExpressionTraitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass"); return ErrorUnexpected; - case Stmt::ExtVectorElementExprClass: + case clang::Stmt::ExtVectorElementExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass"); return ErrorUnexpected; - case Stmt::FloatingLiteralClass: + case clang::Stmt::FloatingLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass"); return ErrorUnexpected; - case Stmt::FunctionParmPackExprClass: + case clang::Stmt::FunctionParmPackExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass"); return ErrorUnexpected; - case Stmt::GNUNullExprClass: + case clang::Stmt::GNUNullExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass"); return ErrorUnexpected; - case Stmt::GenericSelectionExprClass: + case clang::Stmt::GenericSelectionExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass"); return ErrorUnexpected; - case Stmt::ImaginaryLiteralClass: + case clang::Stmt::ImaginaryLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass"); return ErrorUnexpected; - case Stmt::ImplicitValueInitExprClass: + case clang::Stmt::ImplicitValueInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass"); return ErrorUnexpected; - case Stmt::InitListExprClass: + case clang::Stmt::InitListExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass"); return ErrorUnexpected; - case Stmt::LambdaExprClass: + case clang::Stmt::LambdaExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass"); return ErrorUnexpected; - case Stmt::MSPropertyRefExprClass: + case clang::Stmt::MSPropertyRefExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass"); return ErrorUnexpected; - case Stmt::MSPropertySubscriptExprClass: + case clang::Stmt::MSPropertySubscriptExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass"); return ErrorUnexpected; - case Stmt::MaterializeTemporaryExprClass: + case clang::Stmt::MaterializeTemporaryExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); return ErrorUnexpected; - case Stmt::NoInitExprClass: + case clang::Stmt::NoInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); return ErrorUnexpected; - case Stmt::OMPArraySectionExprClass: + case clang::Stmt::OMPArraySectionExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass"); return ErrorUnexpected; - case Stmt::ObjCArrayLiteralClass: + case clang::Stmt::ObjCArrayLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass"); return ErrorUnexpected; - case Stmt::ObjCAvailabilityCheckExprClass: + case clang::Stmt::ObjCAvailabilityCheckExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass"); return ErrorUnexpected; - case Stmt::ObjCBoolLiteralExprClass: + case clang::Stmt::ObjCBoolLiteralExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass"); return ErrorUnexpected; - case Stmt::ObjCBoxedExprClass: + case clang::Stmt::ObjCBoxedExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass"); return ErrorUnexpected; - case Stmt::ObjCDictionaryLiteralClass: + case clang::Stmt::ObjCDictionaryLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass"); return ErrorUnexpected; - case Stmt::ObjCEncodeExprClass: + case clang::Stmt::ObjCEncodeExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass"); return ErrorUnexpected; - case Stmt::ObjCIndirectCopyRestoreExprClass: + case clang::Stmt::ObjCIndirectCopyRestoreExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); return ErrorUnexpected; - case Stmt::ObjCIsaExprClass: + case clang::Stmt::ObjCIsaExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass"); return ErrorUnexpected; - case Stmt::ObjCIvarRefExprClass: + case clang::Stmt::ObjCIvarRefExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass"); return ErrorUnexpected; - case Stmt::ObjCMessageExprClass: + case clang::Stmt::ObjCMessageExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass"); return ErrorUnexpected; - case Stmt::ObjCPropertyRefExprClass: + case clang::Stmt::ObjCPropertyRefExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass"); return ErrorUnexpected; - case Stmt::ObjCProtocolExprClass: + case clang::Stmt::ObjCProtocolExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass"); return ErrorUnexpected; - case Stmt::ObjCSelectorExprClass: + case clang::Stmt::ObjCSelectorExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass"); return ErrorUnexpected; - case Stmt::ObjCStringLiteralClass: + case clang::Stmt::ObjCStringLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass"); return ErrorUnexpected; - case Stmt::ObjCSubscriptRefExprClass: + case clang::Stmt::ObjCSubscriptRefExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass"); return ErrorUnexpected; - case Stmt::OffsetOfExprClass: + case clang::Stmt::OffsetOfExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass"); return ErrorUnexpected; - case Stmt::OpaqueValueExprClass: + case clang::Stmt::OpaqueValueExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass"); return ErrorUnexpected; - case Stmt::UnresolvedLookupExprClass: + case clang::Stmt::UnresolvedLookupExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass"); return ErrorUnexpected; - case Stmt::UnresolvedMemberExprClass: + case clang::Stmt::UnresolvedMemberExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass"); return ErrorUnexpected; - case Stmt::PackExpansionExprClass: + case clang::Stmt::PackExpansionExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); return ErrorUnexpected; - case Stmt::ParenListExprClass: + case clang::Stmt::ParenListExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); return ErrorUnexpected; - case Stmt::PredefinedExprClass: + case clang::Stmt::PredefinedExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); return ErrorUnexpected; - case Stmt::PseudoObjectExprClass: + case clang::Stmt::PseudoObjectExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); return ErrorUnexpected; - case Stmt::ShuffleVectorExprClass: + case clang::Stmt::ShuffleVectorExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass"); return ErrorUnexpected; - case Stmt::SizeOfPackExprClass: + case clang::Stmt::SizeOfPackExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); return ErrorUnexpected; - case Stmt::StmtExprClass: + case clang::Stmt::StmtExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); return ErrorUnexpected; - case Stmt::SubstNonTypeTemplateParmExprClass: + case clang::Stmt::SubstNonTypeTemplateParmExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); return ErrorUnexpected; - case Stmt::SubstNonTypeTemplateParmPackExprClass: + case clang::Stmt::SubstNonTypeTemplateParmPackExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); return ErrorUnexpected; - case Stmt::TypeTraitExprClass: + case clang::Stmt::TypeTraitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass"); return ErrorUnexpected; - case Stmt::TypoExprClass: + case clang::Stmt::TypoExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); return ErrorUnexpected; - case Stmt::VAArgExprClass: + case clang::Stmt::VAArgExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); return ErrorUnexpected; - case Stmt::GotoStmtClass: + case clang::Stmt::GotoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); return ErrorUnexpected; - case Stmt::IndirectGotoStmtClass: + case clang::Stmt::IndirectGotoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); return ErrorUnexpected; - case Stmt::LabelStmtClass: + case clang::Stmt::LabelStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass"); return ErrorUnexpected; - case Stmt::MSDependentExistsStmtClass: + case clang::Stmt::MSDependentExistsStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); return ErrorUnexpected; - case Stmt::OMPAtomicDirectiveClass: + case clang::Stmt::OMPAtomicDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPBarrierDirectiveClass: + case clang::Stmt::OMPBarrierDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPCancelDirectiveClass: + case clang::Stmt::OMPCancelDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPCancellationPointDirectiveClass: + case clang::Stmt::OMPCancellationPointDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPCriticalDirectiveClass: + case clang::Stmt::OMPCriticalDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPFlushDirectiveClass: + case clang::Stmt::OMPFlushDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPDistributeDirectiveClass: + case clang::Stmt::OMPDistributeDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPDistributeParallelForDirectiveClass: + case clang::Stmt::OMPDistributeParallelForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPDistributeParallelForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPDistributeSimdDirectiveClass: + case clang::Stmt::OMPDistributeSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPForDirectiveClass: + case clang::Stmt::OMPForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPForSimdDirectiveClass: + case clang::Stmt::OMPForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPParallelForDirectiveClass: + case clang::Stmt::OMPParallelForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPParallelForSimdDirectiveClass: + case clang::Stmt::OMPParallelForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPSimdDirectiveClass: + case clang::Stmt::OMPSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetParallelForSimdDirectiveClass: + case clang::Stmt::OMPTargetParallelForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetSimdDirectiveClass: + case clang::Stmt::OMPTargetSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetTeamsDistributeDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: + case clang::Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskLoopDirectiveClass: + case clang::Stmt::OMPTaskLoopDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskLoopSimdDirectiveClass: + case clang::Stmt::OMPTaskLoopSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTeamsDistributeDirectiveClass: + case clang::Stmt::OMPTeamsDistributeDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTeamsDistributeParallelForDirectiveClass: + case clang::Stmt::OMPTeamsDistributeParallelForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: + case clang::Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTeamsDistributeSimdDirectiveClass: + case clang::Stmt::OMPTeamsDistributeSimdDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPMasterDirectiveClass: + case clang::Stmt::OMPMasterDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPOrderedDirectiveClass: + case clang::Stmt::OMPOrderedDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPParallelDirectiveClass: + case clang::Stmt::OMPParallelDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPParallelSectionsDirectiveClass: + case clang::Stmt::OMPParallelSectionsDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPSectionDirectiveClass: + case clang::Stmt::OMPSectionDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPSectionsDirectiveClass: + case clang::Stmt::OMPSectionsDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPSingleDirectiveClass: + case clang::Stmt::OMPSingleDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetDataDirectiveClass: + case clang::Stmt::OMPTargetDataDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetDirectiveClass: + case clang::Stmt::OMPTargetDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetEnterDataDirectiveClass: + case clang::Stmt::OMPTargetEnterDataDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetExitDataDirectiveClass: + case clang::Stmt::OMPTargetExitDataDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetParallelDirectiveClass: + case clang::Stmt::OMPTargetParallelDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetParallelForDirectiveClass: + case clang::Stmt::OMPTargetParallelForDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetTeamsDirectiveClass: + case clang::Stmt::OMPTargetTeamsDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTargetUpdateDirectiveClass: + case clang::Stmt::OMPTargetUpdateDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskDirectiveClass: + case clang::Stmt::OMPTaskDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskgroupDirectiveClass: + case clang::Stmt::OMPTaskgroupDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskwaitDirectiveClass: + case clang::Stmt::OMPTaskwaitDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTaskyieldDirectiveClass: + case clang::Stmt::OMPTaskyieldDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass"); return ErrorUnexpected; - case Stmt::OMPTeamsDirectiveClass: + case clang::Stmt::OMPTeamsDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass"); return ErrorUnexpected; - case Stmt::ObjCAtCatchStmtClass: + case clang::Stmt::ObjCAtCatchStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass"); return ErrorUnexpected; - case Stmt::ObjCAtFinallyStmtClass: + case clang::Stmt::ObjCAtFinallyStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass"); return ErrorUnexpected; - case Stmt::ObjCAtSynchronizedStmtClass: + case clang::Stmt::ObjCAtSynchronizedStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass"); return ErrorUnexpected; - case Stmt::ObjCAtThrowStmtClass: + case clang::Stmt::ObjCAtThrowStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass"); return ErrorUnexpected; - case Stmt::ObjCAtTryStmtClass: + case clang::Stmt::ObjCAtTryStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass"); return ErrorUnexpected; - case Stmt::ObjCAutoreleasePoolStmtClass: + case clang::Stmt::ObjCAutoreleasePoolStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass"); return ErrorUnexpected; - case Stmt::ObjCForCollectionStmtClass: + case clang::Stmt::ObjCForCollectionStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass"); return ErrorUnexpected; - case Stmt::SEHExceptStmtClass: + case clang::Stmt::SEHExceptStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass"); return ErrorUnexpected; - case Stmt::SEHFinallyStmtClass: + case clang::Stmt::SEHFinallyStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass"); return ErrorUnexpected; - case Stmt::SEHLeaveStmtClass: + case clang::Stmt::SEHLeaveStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass"); return ErrorUnexpected; - case Stmt::SEHTryStmtClass: + case clang::Stmt::SEHTryStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass"); return ErrorUnexpected; - case Stmt::FixedPointLiteralClass: + case clang::Stmt::FixedPointLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C FixedPointLiteralClass"); return ErrorUnexpected; } @@ -3679,7 +3677,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, } // Returns null if there was an error -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, +static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval) { AstNode *result_node; @@ -3692,7 +3690,7 @@ static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope // Statements have no result and no concept of L or R value. // Returns child scope, or null if there was an error -static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node) { +static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node) { TransScope *child_scope; if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) { return nullptr; @@ -3700,7 +3698,7 @@ static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, A return child_scope; } -static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { +static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) { Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); if (get_global(c, fn_name)) { @@ -3717,13 +3715,13 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { proto_node->data.fn_proto.name = fn_name; proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); - StorageClass sc = fn_decl->getStorageClass(); - if (sc == SC_None) { + clang::StorageClass sc = fn_decl->getStorageClass(); + if (sc == clang::SC_None) { proto_node->data.fn_proto.visib_mod = c->visib_mod; proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false; - } else if (sc == SC_Extern || sc == SC_Static) { + } else if (sc == clang::SC_Extern || sc == clang::SC_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; - } else if (sc == SC_PrivateExtern) { + } else if (sc == clang::SC_PrivateExtern) { emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); return; } else { @@ -3735,7 +3733,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { AstNode *param_node = proto_node->data.fn_proto.params.at(i); - const ParmVarDecl *param = fn_decl->getParamDecl(i); + const clang::ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); Buf *proto_param_name; @@ -3762,7 +3760,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { // actual function definition with body c->ptr_params.clear(); - Stmt *body = fn_decl->getBody(); + clang::Stmt *body = fn_decl->getBody(); AstNode *actual_body_node; TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node); if (result_scope == nullptr) { @@ -3804,19 +3802,19 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); } -static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { +static AstNode *resolve_typdef_as_builtin(Context *c, const clang::TypedefNameDecl *typedef_decl, const char *primitive_name) { AstNode *node = trans_create_node_symbol_str(c, primitive_name); c->decl_table.put(typedef_decl, node); return node; } -static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { +static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl) { auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; } - QualType child_qt = typedef_decl->getUnderlyingType(); + clang::QualType child_qt = typedef_decl->getUnderlyingType(); Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); if (buf_eql_str(type_name, "uint8_t")) { @@ -3865,7 +3863,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_ return symbol_node; } -struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, +struct AstNode *demote_enum_to_opaque(Context *c, const clang::EnumDecl *enum_decl, Buf *full_type_name, Buf *bare_name) { AstNode *opaque_node = trans_create_node_opaque(c); @@ -3880,7 +3878,7 @@ struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, return symbol_node; } -static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { +static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) { auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; @@ -3891,7 +3889,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); - const EnumDecl *enum_def = enum_decl->getDefinition(); + const clang::EnumDecl *enum_def = enum_decl->getDefinition(); if (!enum_def) { return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); } @@ -3903,7 +3901,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { it_end = enum_def->enumerator_end(); it != it_end; ++it, field_count += 1) { - const EnumConstantDecl *enum_const = *it; + const clang::EnumConstantDecl *enum_const = *it; if (enum_const->getInitExpr()) { pure_enum = false; } @@ -3917,8 +3915,8 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { // TODO only emit this tag type if the enum tag type is not the default. // I don't know what the default is, need to figure out how clang is deciding. // it appears to at least be different across gcc/msvc - if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && - !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) + if (!c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::UInt) && + !c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::Int)) { enum_node->data.container_decl.init_arg_expr = tag_int_type; } @@ -3928,7 +3926,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { it_end = enum_def->enumerator_end(); it != it_end; ++it, i += 1) { - const EnumConstantDecl *enum_const = *it; + const clang::EnumConstantDecl *enum_const = *it; Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); Buf *field_name; @@ -3969,7 +3967,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { } } -static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, +static AstNode *demote_struct_to_opaque(Context *c, const clang::RecordDecl *record_decl, Buf *full_type_name, Buf *bare_name) { AstNode *opaque_node = trans_create_node_opaque(c); @@ -3984,7 +3982,7 @@ static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_dec return symbol_node; } -static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { +static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl) { auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); if (existing_entry) { return existing_entry->value; @@ -4010,7 +4008,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { Buf *full_type_name = (bare_name == nullptr) ? nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); - RecordDecl *record_def = record_decl->getDefinition(); + clang::RecordDecl *record_def = record_decl->getDefinition(); if (record_def == nullptr) { return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); } @@ -4021,7 +4019,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { it_end = record_def->field_end(); it != it_end; ++it, field_count += 1) { - const FieldDecl *field_decl = *it; + const clang::FieldDecl *field_decl = *it; if (field_decl->isBitField()) { emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield", @@ -4051,7 +4049,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { it_end = record_def->field_end(); it != it_end; ++it, i += 1) { - const FieldDecl *field_decl = *it; + const clang::FieldDecl *field_decl = *it; AstNode *field_node = trans_create_node(c, NodeTypeStructField); field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); @@ -4078,13 +4076,13 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { } } -static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const SourceLocation &source_loc) { +static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::QualType qt, const clang::SourceLocation &source_loc) { switch (ap_value->getKind()) { - case APValue::Int: + case clang::APValue::Int: return trans_create_node_apint(c, ap_value->getInt()); - case APValue::Uninitialized: + case clang::APValue::Uninitialized: return trans_create_node(c, NodeTypeUndefinedLiteral); - case APValue::Array: { + case clang::APValue::Array: { emit_warning(c, source_loc, "TODO add a test case for this code"); unsigned init_count = ap_value->getArrayInitializedElts(); @@ -4098,10 +4096,10 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const init_node->data.container_init_expr.type = arr_type_node; init_node->data.container_init_expr.kind = ContainerInitKindArray; - QualType child_qt = qt.getTypePtr()->getAsArrayTypeUnsafe()->getElementType(); + clang::QualType child_qt = qt.getTypePtr()->getAsArrayTypeUnsafe()->getElementType(); for (size_t i = 0; i < init_count; i += 1) { - APValue &elem_ap_val = ap_value->getArrayInitializedElt(i); + clang::APValue &elem_ap_val = ap_value->getArrayInitializedElt(i); AstNode *elem_node = trans_ap_value(c, &elem_ap_val, child_qt, source_loc); if (elem_node == nullptr) return nullptr; @@ -4111,7 +4109,7 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const return init_node; } - APValue &filler_ap_val = ap_value->getArrayFiller(); + clang::APValue &filler_ap_val = ap_value->getArrayFiller(); AstNode *filler_node = trans_ap_value(c, &filler_ap_val, child_qt, source_loc); if (filler_node == nullptr) return nullptr; @@ -4139,60 +4137,60 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node); } - case APValue::LValue: { - const APValue::LValueBase lval_base = ap_value->getLValueBase(); - if (const Expr *expr = lval_base.dyn_cast()) { + case clang::APValue::LValue: { + const clang::APValue::LValueBase lval_base = ap_value->getLValueBase(); + if (const clang::Expr *expr = lval_base.dyn_cast()) { return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue); } - //const ValueDecl *value_decl = lval_base.get(); - emit_warning(c, source_loc, "TODO handle initializer LValue ValueDecl"); + //const clang::ValueDecl *value_decl = lval_base.get(); + emit_warning(c, source_loc, "TODO handle initializer LValue clang::ValueDecl"); return nullptr; } - case APValue::Float: + case clang::APValue::Float: emit_warning(c, source_loc, "unsupported initializer value kind: Float"); return nullptr; - case APValue::ComplexInt: + case clang::APValue::ComplexInt: emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt"); return nullptr; - case APValue::ComplexFloat: + case clang::APValue::ComplexFloat: emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat"); return nullptr; - case APValue::Vector: + case clang::APValue::Vector: emit_warning(c, source_loc, "unsupported initializer value kind: Vector"); return nullptr; - case APValue::Struct: + case clang::APValue::Struct: emit_warning(c, source_loc, "unsupported initializer value kind: Struct"); return nullptr; - case APValue::Union: + case clang::APValue::Union: emit_warning(c, source_loc, "unsupported initializer value kind: Union"); return nullptr; - case APValue::MemberPointer: + case clang::APValue::MemberPointer: emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer"); return nullptr; - case APValue::AddrLabelDiff: + case clang::APValue::AddrLabelDiff: emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff"); return nullptr; } zig_unreachable(); } -static void visit_var_decl(Context *c, const VarDecl *var_decl) { +static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) { Buf *name = buf_create_from_str(decl_name(var_decl)); switch (var_decl->getTLSKind()) { - case VarDecl::TLS_None: + case clang::VarDecl::TLS_None: break; - case VarDecl::TLS_Static: + case clang::VarDecl::TLS_Static: emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - static thread local storage", buf_ptr(name)); return; - case VarDecl::TLS_Dynamic: + case clang::VarDecl::TLS_Dynamic: emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); return; } - QualType qt = var_decl->getType(); + clang::QualType qt = var_decl->getType(); AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); if (var_type == nullptr) { emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); @@ -4206,7 +4204,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { if (is_static && !is_extern) { AstNode *init_node; if (var_decl->hasInit()) { - APValue *ap_value = var_decl->evaluateValue(); + clang::APValue *ap_value = var_decl->evaluateValue(); if (ap_value == nullptr) { emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); @@ -4236,24 +4234,24 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { return; } -static bool decl_visitor(void *context, const Decl *decl) { +static bool decl_visitor(void *context, const clang::Decl *decl) { Context *c = (Context*)context; switch (decl->getKind()) { - case Decl::Function: - visit_fn_decl(c, static_cast(decl)); + case clang::Decl::Function: + visit_fn_decl(c, static_cast(decl)); break; - case Decl::Typedef: - resolve_typedef_decl(c, static_cast(decl)); + case clang::Decl::Typedef: + resolve_typedef_decl(c, static_cast(decl)); break; - case Decl::Enum: - resolve_enum_decl(c, static_cast(decl)); + case clang::Decl::Enum: + resolve_enum_decl(c, static_cast(decl)); break; - case Decl::Record: - resolve_record_decl(c, static_cast(decl)); + case clang::Decl::Record: + resolve_record_decl(c, static_cast(decl)); break; - case Decl::Var: - visit_var_decl(c, static_cast(decl)); + case clang::Decl::Var: + visit_var_decl(c, static_cast(decl)); break; default: emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); @@ -4674,24 +4672,24 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch c->macro_table.put(name, result_node); } -static void process_preprocessor_entities(Context *c, ASTUnit &unit) { +static void process_preprocessor_entities(Context *c, clang::ASTUnit &unit) { CTokenize ctok = {{0}}; // TODO if we see #undef, delete it from the table - for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { + for (clang::PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { switch (entity->getKind()) { - case PreprocessedEntity::InvalidKind: - case PreprocessedEntity::InclusionDirectiveKind: - case PreprocessedEntity::MacroExpansionKind: + case clang::PreprocessedEntity::InvalidKind: + case clang::PreprocessedEntity::InclusionDirectiveKind: + case clang::PreprocessedEntity::MacroExpansionKind: continue; - case PreprocessedEntity::MacroDefinitionKind: + case clang::PreprocessedEntity::MacroDefinitionKind: { - MacroDefinitionRecord *macro = static_cast(entity); + clang::MacroDefinitionRecord *macro = static_cast(entity); const char *raw_name = macro->getName()->getNameStart(); - SourceRange range = macro->getSourceRange(); - SourceLocation begin_loc = range.getBegin(); - SourceLocation end_loc = range.getEnd(); + clang::SourceRange range = macro->getSourceRange(); + clang::SourceLocation begin_loc = range.getBegin(); + clang::SourceLocation end_loc = range.getEnd(); if (begin_loc == end_loc) { // this means it is a macro without a value @@ -4816,9 +4814,9 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const // to make the [start...end] argument work clang_argv.append(nullptr); - IntrusiveRefCntPtr diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); + clang::IntrusiveRefCntPtr diags(clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions)); - std::shared_ptr pch_container_ops = std::make_shared(); + std::shared_ptr pch_container_ops = std::make_shared(); bool only_local_decls = true; bool capture_diagnostics = true; @@ -4827,13 +4825,13 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const bool single_file_parse = false; bool for_serialization = false; const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); - std::unique_ptr err_unit; - std::unique_ptr ast_unit(ASTUnit::LoadFromCommandLine( + std::unique_ptr err_unit; + std::unique_ptr ast_unit(clang::ASTUnit::LoadFromCommandLine( &clang_argv.at(0), &clang_argv.last(), pch_container_ops, diags, resources_path, - only_local_decls, capture_diagnostics, None, true, 0, TU_Complete, - false, false, allow_pch_with_compiler_errors, SkipFunctionBodiesScope::None, - single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit, + only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete, + false, false, allow_pch_with_compiler_errors, clang::SkipFunctionBodiesScope::None, + single_file_parse, user_files_are_volatile, for_serialization, clang::None, &err_unit, nullptr)); // Early failures in LoadFromCommandLine may return with ErrUnit unset. @@ -4846,26 +4844,26 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const err_unit = std::move(ast_unit); } - for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), + for (clang::ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), it_end = err_unit->stored_diag_end(); it != it_end; ++it) { switch (it->getLevel()) { - case DiagnosticsEngine::Ignored: - case DiagnosticsEngine::Note: - case DiagnosticsEngine::Remark: - case DiagnosticsEngine::Warning: + case clang::DiagnosticsEngine::Ignored: + case clang::DiagnosticsEngine::Note: + case clang::DiagnosticsEngine::Remark: + case clang::DiagnosticsEngine::Warning: continue; - case DiagnosticsEngine::Error: - case DiagnosticsEngine::Fatal: + case clang::DiagnosticsEngine::Error: + case clang::DiagnosticsEngine::Fatal: break; } StringRef msg_str_ref = it->getMessage(); Buf *msg = string_ref_to_buf(msg_str_ref); - FullSourceLoc fsl = it->getLocation(); + clang::FullSourceLoc fsl = it->getLocation(); if (fsl.hasManager()) { - FileID file_id = fsl.getFileID(); - StringRef filename = fsl.getManager().getFilename(fsl); + clang::FileID file_id = fsl.getFileID(); + clang::StringRef filename = fsl.getManager().getFilename(fsl); unsigned line = fsl.getSpellingLineNumber() - 1; unsigned column = fsl.getSpellingColumnNumber() - 1; unsigned offset = fsl.getManager().getFileOffset(fsl); From bd52d81dc316df601877a17a9c70caf3a49f936d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 14:36:28 -0500 Subject: [PATCH 212/218] README: direct link to Download & Documentation at the top --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b64d75c11..3ac4f429f2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A programming language designed for robustness, optimality, and clarity. -[ziglang.org](https://ziglang.org) +[Download & Documentation](https://ziglang.org/download/) ## Feature Highlights From 356cfa08f49a9e92dfa4135cbcf2ddc079ddf228 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 15:14:51 -0500 Subject: [PATCH 213/218] translate-c: proof of concept for transitioning to userland See #1964 --- CMakeLists.txt | 1 + src/translate_c.cpp | 22 ++-- src/zig_clang.cpp | 178 +++++++++++++++++++++++++++++++ src/zig_clang.h | 253 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 446 insertions(+), 8 deletions(-) create mode 100644 src/zig_clang.cpp create mode 100644 src/zig_clang.h diff --git a/CMakeLists.txt b/CMakeLists.txt index db5f50908c..b633e01978 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,6 +429,7 @@ set(BLAKE_SOURCES ) set(ZIG_CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" + "${CMAKE_SOURCE_DIR}/src/zig_clang.cpp" "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" ) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 7d618466b2..7462c8e046 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -14,7 +14,6 @@ #include "translate_c.hpp" #include "parser.hpp" - #if __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" @@ -28,6 +27,13 @@ #pragma GCC diagnostic pop #endif + +// Before the #include of zig_clang.h +// Temporary transitional thing: override ZigClangSourceLocation with clang::SourceLocation +#define ZigClangSourceLocation clang::SourceLocation +#define ZIG_CLANG_SOURCE_LOCATION ZigClangABISourceLocation +#include "zig_clang.h" + #include struct Alias { @@ -85,7 +91,7 @@ struct Context { HashMap decl_table; HashMap macro_table; HashMap global_table; - clang::SourceManager *source_manager; + ZigClangSourceManager *source_manager; ZigList aliases; AstNode *source_node; bool warnings_on; @@ -139,16 +145,16 @@ static void emit_warning(Context *c, const clang::SourceLocation &sl, const char Buf *msg = buf_vprintf(format, ap); va_end(ap); - StringRef filename = c->source_manager->getFilename(c->source_manager->getSpellingLoc(sl)); - const char *filename_bytes = (const char *)filename.bytes_begin(); + const char *filename_bytes = ZigClangSourceManager_getFilename(c->source_manager, + ZigClangSourceManager_getSpellingLoc(c->source_manager, sl)); Buf *path; if (filename_bytes) { path = buf_create_from_str(filename_bytes); } else { path = buf_sprintf("(no file)"); } - unsigned line = c->source_manager->getSpellingLineNumber(sl); - unsigned column = c->source_manager->getSpellingColumnNumber(sl); + unsigned line = ZigClangSourceManager_getSpellingLineNumber(c->source_manager, sl); + unsigned column = ZigClangSourceManager_getSpellingColumnNumber(c->source_manager, sl); fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); } @@ -4701,7 +4707,7 @@ static void process_preprocessor_entities(Context *c, clang::ASTUnit &unit) { continue; } - const char *begin_c = c->source_manager->getCharacterData(begin_loc); + const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, begin_loc); process_macro(c, &ctok, name, begin_c); } } @@ -4889,7 +4895,7 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const } c->ctx = &ast_unit->getASTContext(); - c->source_manager = &ast_unit->getSourceManager(); + c->source_manager = reinterpret_cast(&ast_unit->getSourceManager()); c->root = trans_create_node(c, NodeTypeContainerDecl); c->root->data.container_decl.is_root = true; diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp new file mode 100644 index 0000000000..62d1e34658 --- /dev/null +++ b/src/zig_clang.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + + +/* + * The point of this file is to contain all the Clang C++ API interaction so that: + * 1. The compile time of other files is kept under control. + * 2. Provide a C interface to the Clang functions we need for self-hosting purposes. + * 3. Prevent C++ from infecting the rest of the project. + */ + +#if __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + +#include +#include +#include + +#if __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif + +// Before the #include of zig_clang.h +// We'll check that the types are compatible but just use +// the clang type. +#define ZigClangSourceLocation clang::SourceLocation +#define ZIG_CLANG_SOURCE_LOCATION ZigClangABISourceLocation + +#include "zig_clang.h" + +// Detect additions to the enum +void zig2clang_BO(ZigClangBO op) { + switch (op) { + case ZigClangBO_PtrMemD: + case ZigClangBO_PtrMemI: + case ZigClangBO_Cmp: + case ZigClangBO_Mul: + case ZigClangBO_Div: + case ZigClangBO_Rem: + case ZigClangBO_Add: + case ZigClangBO_Sub: + case ZigClangBO_Shl: + case ZigClangBO_Shr: + case ZigClangBO_LT: + case ZigClangBO_GT: + case ZigClangBO_LE: + case ZigClangBO_GE: + case ZigClangBO_EQ: + case ZigClangBO_NE: + case ZigClangBO_And: + case ZigClangBO_Xor: + case ZigClangBO_Or: + case ZigClangBO_LAnd: + case ZigClangBO_LOr: + case ZigClangBO_Assign: + case ZigClangBO_Comma: + case ZigClangBO_MulAssign: + case ZigClangBO_DivAssign: + case ZigClangBO_RemAssign: + case ZigClangBO_AddAssign: + case ZigClangBO_SubAssign: + case ZigClangBO_ShlAssign: + case ZigClangBO_ShrAssign: + case ZigClangBO_AndAssign: + case ZigClangBO_XorAssign: + case ZigClangBO_OrAssign: + break; + } +} + +static_assert((clang::BinaryOperatorKind)ZigClangBO_Add == clang::BO_Add, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_AddAssign == clang::BO_AddAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_And == clang::BO_And, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_AndAssign == clang::BO_AndAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Assign == clang::BO_Assign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Cmp == clang::BO_Cmp, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Comma == clang::BO_Comma, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Div == clang::BO_Div, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_DivAssign == clang::BO_DivAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_EQ == clang::BO_EQ, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_GE == clang::BO_GE, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_GT == clang::BO_GT, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_LAnd == clang::BO_LAnd, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_LE == clang::BO_LE, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_LOr == clang::BO_LOr, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_LT == clang::BO_LT, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Mul == clang::BO_Mul, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_MulAssign == clang::BO_MulAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_NE == clang::BO_NE, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Or == clang::BO_Or, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_OrAssign == clang::BO_OrAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemD == clang::BO_PtrMemD, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemI == clang::BO_PtrMemI, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Rem == clang::BO_Rem, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_RemAssign == clang::BO_RemAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Shl == clang::BO_Shl, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_ShlAssign == clang::BO_ShlAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Shr == clang::BO_Shr, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_ShrAssign == clang::BO_ShrAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Sub == clang::BO_Sub, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_SubAssign == clang::BO_SubAssign, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_Xor == clang::BO_Xor, ""); +static_assert((clang::BinaryOperatorKind)ZigClangBO_XorAssign == clang::BO_XorAssign, ""); + +// This function detects additions to the enum +void zig2clang_UO(ZigClangUO op) { + switch (op) { + case ZigClangUO_AddrOf: + case ZigClangUO_Coawait: + case ZigClangUO_Deref: + case ZigClangUO_Extension: + case ZigClangUO_Imag: + case ZigClangUO_LNot: + case ZigClangUO_Minus: + case ZigClangUO_Not: + case ZigClangUO_Plus: + case ZigClangUO_PostDec: + case ZigClangUO_PostInc: + case ZigClangUO_PreDec: + case ZigClangUO_PreInc: + case ZigClangUO_Real: + break; + } +} + +static_assert((clang::UnaryOperatorKind)ZigClangUO_AddrOf == clang::UO_AddrOf, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Coawait == clang::UO_Coawait, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Deref == clang::UO_Deref, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Extension == clang::UO_Extension, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Imag == clang::UO_Imag, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_LNot == clang::UO_LNot, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Minus == clang::UO_Minus, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Not == clang::UO_Not, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Plus == clang::UO_Plus, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_PostDec == clang::UO_PostDec, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_PostInc == clang::UO_PostInc, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, ""); +static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, ""); + +static_assert(sizeof(ZigClangABISourceLocation) == sizeof(clang::SourceLocation)); + +clang::SourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, + clang::SourceLocation Loc) +{ + return reinterpret_cast(self)->getSpellingLoc(Loc); +} + +const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *self, + clang::SourceLocation SpellingLoc) +{ + StringRef s = reinterpret_cast(self)->getFilename(SpellingLoc); + return (const char *)s.bytes_begin(); +} + +unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *self, + ZigClangSourceLocation Loc) +{ + return reinterpret_cast(self)->getSpellingLineNumber(Loc); +} + +unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *self, + ZigClangSourceLocation Loc) +{ + return reinterpret_cast(self)->getSpellingColumnNumber(Loc); +} + +const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *self, + ZigClangSourceLocation SL) +{ + return reinterpret_cast(self)->getCharacterData(SL); +} diff --git a/src/zig_clang.h b/src/zig_clang.h new file mode 100644 index 0000000000..840d227bb4 --- /dev/null +++ b/src/zig_clang.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_ZIG_CLANG_H +#define ZIG_ZIG_CLANG_H + +#ifdef __cplusplus +#define ZIG_EXTERN_C extern "C" +#else +#define ZIG_EXTERN_C +#endif + +// ATTENTION: If you modify this file, be sure to update the corresponding +// extern function declarations in the self-hosted compiler. + +#ifndef ZIG_CLANG_SOURCE_LOCATION +#define ZIG_CLANG_SOURCE_LOCATION ZigClangSourceLocation +#endif + +struct ZIG_CLANG_SOURCE_LOCATION { + unsigned ID; +}; + +struct ZigClangAPValue; +struct ZigClangASTContext; +struct ZigClangASTUnit; +struct ZigClangArraySubscriptExpr; +struct ZigClangArrayType; +struct ZigClangAttributedType; +struct ZigClangBinaryOperator; +struct ZigClangBreakStmt; +struct ZigClangBuiltinType; +struct ZigClangCStyleCastExpr; +struct ZigClangCallExpr; +struct ZigClangCaseStmt; +struct ZigClangCompoundAssignOperator; +struct ZigClangCompoundStmt; +struct ZigClangConditionalOperator; +struct ZigClangConstantArrayType; +struct ZigClangContinueStmt; +struct ZigClangDecayedType; +struct ZigClangDecl; +struct ZigClangDeclRefExpr; +struct ZigClangDeclStmt; +struct ZigClangDefaultStmt; +struct ZigClangDiagnosticOptions; +struct ZigClangDiagnosticsEngine; +struct ZigClangDoStmt; +struct ZigClangElaboratedType; +struct ZigClangEnumConstantDecl; +struct ZigClangEnumDecl; +struct ZigClangEnumType; +struct ZigClangExpr; +struct ZigClangFieldDecl; +struct ZigClangFileID; +struct ZigClangForStmt; +struct ZigClangFullSourceLoc; +struct ZigClangFunctionDecl; +struct ZigClangFunctionProtoType; +struct ZigClangIfStmt; +struct ZigClangImplicitCastExpr; +struct ZigClangIncompleteArrayType; +struct ZigClangIntegerLiteral; +struct ZigClangMacroDefinitionRecord; +struct ZigClangMemberExpr; +struct ZigClangNamedDecl; +struct ZigClangNone; +struct ZigClangPCHContainerOperations; +struct ZigClangParenExpr; +struct ZigClangParenType; +struct ZigClangParmVarDecl; +struct ZigClangPointerType; +struct ZigClangPreprocessedEntity; +struct ZigClangQualType; +struct ZigClangRecordDecl; +struct ZigClangRecordType; +struct ZigClangReturnStmt; +struct ZigClangSkipFunctionBodiesScope; +struct ZigClangSourceManager; +struct ZigClangSourceRange; +struct ZigClangStmt; +struct ZigClangStorageClass; +struct ZigClangStringLiteral; +struct ZigClangStringRef; +struct ZigClangSwitchStmt; +struct ZigClangType; +struct ZigClangTypedefNameDecl; +struct ZigClangTypedefType; +struct ZigClangUnaryExprOrTypeTraitExpr; +struct ZigClangUnaryOperator; +struct ZigClangValueDecl; +struct ZigClangVarDecl; +struct ZigClangWhileStmt; + +enum ZigClangBO { + ZigClangBO_PtrMemD, + ZigClangBO_PtrMemI, + ZigClangBO_Mul, + ZigClangBO_Div, + ZigClangBO_Rem, + ZigClangBO_Add, + ZigClangBO_Sub, + ZigClangBO_Shl, + ZigClangBO_Shr, + ZigClangBO_Cmp, + ZigClangBO_LT, + ZigClangBO_GT, + ZigClangBO_LE, + ZigClangBO_GE, + ZigClangBO_EQ, + ZigClangBO_NE, + ZigClangBO_And, + ZigClangBO_Xor, + ZigClangBO_Or, + ZigClangBO_LAnd, + ZigClangBO_LOr, + ZigClangBO_Assign, + ZigClangBO_MulAssign, + ZigClangBO_DivAssign, + ZigClangBO_RemAssign, + ZigClangBO_AddAssign, + ZigClangBO_SubAssign, + ZigClangBO_ShlAssign, + ZigClangBO_ShrAssign, + ZigClangBO_AndAssign, + ZigClangBO_XorAssign, + ZigClangBO_OrAssign, + ZigClangBO_Comma, +}; + +enum ZigClangUO { + ZigClangUO_PostInc, + ZigClangUO_PostDec, + ZigClangUO_PreInc, + ZigClangUO_PreDec, + ZigClangUO_AddrOf, + ZigClangUO_Deref, + ZigClangUO_Plus, + ZigClangUO_Minus, + ZigClangUO_Not, + ZigClangUO_LNot, + ZigClangUO_Real, + ZigClangUO_Imag, + ZigClangUO_Extension, + ZigClangUO_Coawait, +}; + +//struct ZigClangCC_AAPCS; +//struct ZigClangCC_AAPCS_VFP; +//struct ZigClangCC_C; +//struct ZigClangCC_IntelOclBicc; +//struct ZigClangCC_OpenCLKernel; +//struct ZigClangCC_PreserveAll; +//struct ZigClangCC_PreserveMost; +//struct ZigClangCC_SpirFunction; +//struct ZigClangCC_Swift; +//struct ZigClangCC_Win64; +//struct ZigClangCC_X86FastCall; +//struct ZigClangCC_X86Pascal; +//struct ZigClangCC_X86RegCall; +//struct ZigClangCC_X86StdCall; +//struct ZigClangCC_X86ThisCall; +//struct ZigClangCC_X86VectorCall; +//struct ZigClangCC_X86_64SysV; + +//struct ZigClangCK_ARCConsumeObject; +//struct ZigClangCK_ARCExtendBlockObject; +//struct ZigClangCK_ARCProduceObject; +//struct ZigClangCK_ARCReclaimReturnedObject; +//struct ZigClangCK_AddressSpaceConversion; +//struct ZigClangCK_AnyPointerToBlockPointerCast; +//struct ZigClangCK_ArrayToPointerDecay; +//struct ZigClangCK_AtomicToNonAtomic; +//struct ZigClangCK_BaseToDerived; +//struct ZigClangCK_BaseToDerivedMemberPointer; +//struct ZigClangCK_BitCast; +//struct ZigClangCK_BlockPointerToObjCPointerCast; +//struct ZigClangCK_BooleanToSignedIntegral; +//struct ZigClangCK_BuiltinFnToFnPtr; +//struct ZigClangCK_CPointerToObjCPointerCast; +//struct ZigClangCK_ConstructorConversion; +//struct ZigClangCK_CopyAndAutoreleaseBlockObject; +//struct ZigClangCK_Dependent; +//struct ZigClangCK_DerivedToBase; +//struct ZigClangCK_DerivedToBaseMemberPointer; +//struct ZigClangCK_Dynamic; +//struct ZigClangCK_FloatingCast; +//struct ZigClangCK_FloatingComplexCast; +//struct ZigClangCK_FloatingComplexToBoolean; +//struct ZigClangCK_FloatingComplexToIntegralComplex; +//struct ZigClangCK_FloatingComplexToReal; +//struct ZigClangCK_FloatingRealToComplex; +//struct ZigClangCK_FloatingToBoolean; +//struct ZigClangCK_FloatingToIntegral; +//struct ZigClangCK_FunctionToPointerDecay; +//struct ZigClangCK_IntToOCLSampler; +//struct ZigClangCK_IntegralCast; +//struct ZigClangCK_IntegralComplexCast; +//struct ZigClangCK_IntegralComplexToBoolean; +//struct ZigClangCK_IntegralComplexToFloatingComplex; +//struct ZigClangCK_IntegralComplexToReal; +//struct ZigClangCK_IntegralRealToComplex; +//struct ZigClangCK_IntegralToBoolean; +//struct ZigClangCK_IntegralToFloating; +//struct ZigClangCK_IntegralToPointer; +//struct ZigClangCK_LValueBitCast; +//struct ZigClangCK_LValueToRValue; +//struct ZigClangCK_MemberPointerToBoolean; +//struct ZigClangCK_NoOp; +//struct ZigClangCK_NonAtomicToAtomic; +//struct ZigClangCK_NullToMemberPointer; +//struct ZigClangCK_NullToPointer; +//struct ZigClangCK_ObjCObjectLValueCast; +//struct ZigClangCK_PointerToBoolean; +//struct ZigClangCK_PointerToIntegral; +//struct ZigClangCK_ReinterpretMemberPointer; +//struct ZigClangCK_ToUnion; +//struct ZigClangCK_ToVoid; +//struct ZigClangCK_UncheckedDerivedToBase; +//struct ZigClangCK_UserDefinedConversion; +//struct ZigClangCK_VectorSplat; +//struct ZigClangCK_ZeroToOCLEvent; +//struct ZigClangCK_ZeroToOCLQueue; + +//struct ZigClangETK_Class; +//struct ZigClangETK_Enum; +//struct ZigClangETK_Interface; +//struct ZigClangETK_None; +//struct ZigClangETK_Struct; +//struct ZigClangETK_Typename; +//struct ZigClangETK_Union; + +//struct ZigClangSC_None; +//struct ZigClangSC_PrivateExtern; +//struct ZigClangSC_Static; + +//struct ZigClangTU_Complete; + +ZIG_EXTERN_C ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *, + ZigClangSourceLocation Loc); +ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *, + ZigClangSourceLocation SpellingLoc); +ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *, + ZigClangSourceLocation Loc); +ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *, + ZigClangSourceLocation Loc); +ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *, + ZigClangSourceLocation SL); +#endif From 2dfa76a1a754d2537b9cc6faf7b98461de0b1429 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 16:17:30 -0500 Subject: [PATCH 214/218] fix regressions from previous commit when building with clang --- src/translate_c.cpp | 20 ++++++++++---------- src/zig_clang.cpp | 39 ++++++++++++++++++++++----------------- src/zig_clang.h | 6 +----- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 7462c8e046..7ebd90e3fe 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4,7 +4,6 @@ * This file is part of zig, which is MIT licensed. * See http://opensource.org/licenses/MIT */ - #include "all_types.hpp" #include "analyze.hpp" #include "c_tokenizer.hpp" @@ -13,6 +12,7 @@ #include "os.hpp" #include "translate_c.hpp" #include "parser.hpp" +#include "zig_clang.h" #if __GNUC__ >= 8 #pragma GCC diagnostic push @@ -27,13 +27,6 @@ #pragma GCC diagnostic pop #endif - -// Before the #include of zig_clang.h -// Temporary transitional thing: override ZigClangSourceLocation with clang::SourceLocation -#define ZigClangSourceLocation clang::SourceLocation -#define ZIG_CLANG_SOURCE_LOCATION ZigClangABISourceLocation -#include "zig_clang.h" - #include struct Alias { @@ -134,8 +127,14 @@ static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc); static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval); +static ZigClangSourceLocation bitcast(clang::SourceLocation src) { + ZigClangSourceLocation dest; + memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); + return dest; +} + ATTRIBUTE_PRINTF(3, 4) -static void emit_warning(Context *c, const clang::SourceLocation &sl, const char *format, ...) { +static void emit_warning(Context *c, const clang::SourceLocation &clang_sl, const char *format, ...) { if (!c->warnings_on) { return; } @@ -145,6 +144,7 @@ static void emit_warning(Context *c, const clang::SourceLocation &sl, const char Buf *msg = buf_vprintf(format, ap); va_end(ap); + ZigClangSourceLocation sl = bitcast(clang_sl); const char *filename_bytes = ZigClangSourceManager_getFilename(c->source_manager, ZigClangSourceManager_getSpellingLoc(c->source_manager, sl)); Buf *path; @@ -4707,7 +4707,7 @@ static void process_preprocessor_entities(Context *c, clang::ASTUnit &unit) { continue; } - const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, begin_loc); + const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, bitcast(begin_loc)); process_macro(c, &ctok, name, begin_c); } } diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 62d1e34658..4e6e4e7a98 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -12,6 +12,7 @@ * 2. Provide a C interface to the Clang functions we need for self-hosting purposes. * 3. Prevent C++ from infecting the rest of the project. */ +#include "zig_clang.h" #if __GNUC__ >= 8 #pragma GCC diagnostic push @@ -26,14 +27,6 @@ #pragma GCC diagnostic pop #endif -// Before the #include of zig_clang.h -// We'll check that the types are compatible but just use -// the clang type. -#define ZigClangSourceLocation clang::SourceLocation -#define ZIG_CLANG_SOURCE_LOCATION ZigClangABISourceLocation - -#include "zig_clang.h" - // Detect additions to the enum void zig2clang_BO(ZigClangBO op) { switch (op) { @@ -144,35 +137,47 @@ static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, " static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, ""); static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, ""); -static_assert(sizeof(ZigClangABISourceLocation) == sizeof(clang::SourceLocation)); +static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), ""); -clang::SourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, - clang::SourceLocation Loc) +static ZigClangSourceLocation bitcast(clang::SourceLocation src) { + ZigClangSourceLocation dest; + memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); + return dest; +} + +static clang::SourceLocation bitcast(ZigClangSourceLocation src) { + clang::SourceLocation dest; + memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); + return dest; +} + +ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, + ZigClangSourceLocation Loc) { - return reinterpret_cast(self)->getSpellingLoc(Loc); + return bitcast(reinterpret_cast(self)->getSpellingLoc(bitcast(Loc))); } const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *self, - clang::SourceLocation SpellingLoc) + ZigClangSourceLocation SpellingLoc) { - StringRef s = reinterpret_cast(self)->getFilename(SpellingLoc); + StringRef s = reinterpret_cast(self)->getFilename(bitcast(SpellingLoc)); return (const char *)s.bytes_begin(); } unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) { - return reinterpret_cast(self)->getSpellingLineNumber(Loc); + return reinterpret_cast(self)->getSpellingLineNumber(bitcast(Loc)); } unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) { - return reinterpret_cast(self)->getSpellingColumnNumber(Loc); + return reinterpret_cast(self)->getSpellingColumnNumber(bitcast(Loc)); } const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *self, ZigClangSourceLocation SL) { - return reinterpret_cast(self)->getCharacterData(SL); + return reinterpret_cast(self)->getCharacterData(bitcast(SL)); } diff --git a/src/zig_clang.h b/src/zig_clang.h index 840d227bb4..78d5cd8cbc 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -17,11 +17,7 @@ // ATTENTION: If you modify this file, be sure to update the corresponding // extern function declarations in the self-hosted compiler. -#ifndef ZIG_CLANG_SOURCE_LOCATION -#define ZIG_CLANG_SOURCE_LOCATION ZigClangSourceLocation -#endif - -struct ZIG_CLANG_SOURCE_LOCATION { +struct ZigClangSourceLocation { unsigned ID; }; From c3c92ca8b1ada4faed14a9770ab7ed6536edaa15 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 19:48:39 -0500 Subject: [PATCH 215/218] translate-c: 4 more functions using C decls See #1964 --- src/translate_c.cpp | 36 ++++++++++++++++++++++++------------ src/zig_clang.cpp | 35 +++++++++++++++++++++++++++++++++-- src/zig_clang.h | 12 +++++++++++- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 7ebd90e3fe..a51a671b06 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -90,7 +90,7 @@ struct Context { bool warnings_on; CodeGen *codegen; - clang::ASTContext *ctx; + ZigClangASTContext *ctx; TransScopeRoot *global_scope; HashMap ptr_params; @@ -132,6 +132,16 @@ static ZigClangSourceLocation bitcast(clang::SourceLocation src) { memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); return dest; } +static ZigClangQualType bitcast(clang::QualType src) { + ZigClangQualType dest; + memcpy(&dest, &src, sizeof(ZigClangQualType)); + return dest; +} +static clang::QualType bitcast(ZigClangQualType src) { + clang::QualType dest; + memcpy(&dest, &src, sizeof(ZigClangQualType)); + return dest; +} ATTRIBUTE_PRINTF(3, 4) static void emit_warning(Context *c, const clang::SourceLocation &clang_sl, const char *format, ...) { @@ -509,7 +519,7 @@ static clang::QualType get_expr_qual_type(Context *c, const clang::Expr *expr) { const clang::ArrayType *array_type = static_cast(array_qt.getTypePtr()); clang::QualType pointee_qt = array_type->getElementType(); pointee_qt.addConst(); - return c->ctx->getPointerType(pointee_qt); + return bitcast(ZigClangASTContext_getPointerType(c->ctx, bitcast(pointee_qt))); } } } @@ -1221,7 +1231,7 @@ static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::Re static AstNode *trans_integer_literal(Context *c, const clang::IntegerLiteral *stmt) { llvm::APSInt result; - if (!stmt->EvaluateAsInt(result, *c->ctx)) { + if (!stmt->EvaluateAsInt(result, *reinterpret_cast(c->ctx))) { emit_warning(c, stmt->getLocStart(), "invalid integer literal"); return nullptr; } @@ -4240,7 +4250,8 @@ static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) { return; } -static bool decl_visitor(void *context, const clang::Decl *decl) { +static bool decl_visitor(void *context, const ZigClangDecl *zdecl) { + const clang::Decl *decl = reinterpret_cast(zdecl); Context *c = (Context*)context; switch (decl->getKind()) { @@ -4678,12 +4689,13 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch c->macro_table.put(name, result_node); } -static void process_preprocessor_entities(Context *c, clang::ASTUnit &unit) { +static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) { + clang::ASTUnit *unit = reinterpret_cast(zunit); CTokenize ctok = {{0}}; // TODO if we see #undef, delete it from the table - for (clang::PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { + for (clang::PreprocessedEntity *entity : unit->getLocalPreprocessingEntities()) { switch (entity->getKind()) { case clang::PreprocessedEntity::InvalidKind: case clang::PreprocessedEntity::InclusionDirectiveKind: @@ -4832,7 +4844,7 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const bool for_serialization = false; const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); std::unique_ptr err_unit; - std::unique_ptr ast_unit(clang::ASTUnit::LoadFromCommandLine( + ZigClangASTUnit *ast_unit = reinterpret_cast(clang::ASTUnit::LoadFromCommandLine( &clang_argv.at(0), &clang_argv.last(), pch_container_ops, diags, resources_path, only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete, @@ -4847,7 +4859,7 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const if (diags->getClient()->getNumErrors() > 0) { if (ast_unit) { - err_unit = std::move(ast_unit); + err_unit = std::unique_ptr(reinterpret_cast(ast_unit)); } for (clang::ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), @@ -4894,14 +4906,14 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const return ErrorCCompileErrors; } - c->ctx = &ast_unit->getASTContext(); - c->source_manager = reinterpret_cast(&ast_unit->getSourceManager()); + c->ctx = ZigClangASTUnit_getASTContext(ast_unit); + c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit); c->root = trans_create_node(c, NodeTypeContainerDecl); c->root->data.container_decl.is_root = true; - ast_unit->visitLocalTopLevelDecls(c, decl_visitor); + ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, decl_visitor); - process_preprocessor_entities(c, *ast_unit); + process_preprocessor_entities(c, ast_unit); render_macros(c); render_aliases(c); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 4e6e4e7a98..4220d778a0 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -138,19 +138,29 @@ static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, " static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, ""); static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), ""); - static ZigClangSourceLocation bitcast(clang::SourceLocation src) { ZigClangSourceLocation dest; memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); return dest; } - static clang::SourceLocation bitcast(ZigClangSourceLocation src) { clang::SourceLocation dest; memcpy(&dest, &src, sizeof(ZigClangSourceLocation)); return dest; } +static_assert(sizeof(ZigClangQualType) == sizeof(clang::QualType), ""); +static ZigClangQualType bitcast(clang::QualType src) { + ZigClangQualType dest; + memcpy(&dest, &src, sizeof(ZigClangQualType)); + return dest; +} +static clang::QualType bitcast(ZigClangQualType src) { + clang::QualType dest; + memcpy(&dest, &src, sizeof(ZigClangQualType)); + return dest; +} + ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) { @@ -181,3 +191,24 @@ const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager * { return reinterpret_cast(self)->getCharacterData(bitcast(SL)); } + +ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* self, ZigClangQualType T) { + return bitcast(reinterpret_cast(self)->getPointerType(bitcast(T))); +} + +ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) { + clang::ASTContext *result = &reinterpret_cast(self)->getASTContext(); + return reinterpret_cast(result); +} + +ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) { + clang::SourceManager *result = &reinterpret_cast(self)->getSourceManager(); + return reinterpret_cast(result); +} + +bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context, + bool (*Fn)(void *context, const ZigClangDecl *decl)) +{ + return reinterpret_cast(self)->visitLocalTopLevelDecls(context, + reinterpret_cast(Fn)); +} diff --git a/src/zig_clang.h b/src/zig_clang.h index 78d5cd8cbc..c7d749cbd9 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -21,6 +21,10 @@ struct ZigClangSourceLocation { unsigned ID; }; +struct ZigClangQualType { + void *ptr; +}; + struct ZigClangAPValue; struct ZigClangASTContext; struct ZigClangASTUnit; @@ -71,7 +75,6 @@ struct ZigClangParenType; struct ZigClangParmVarDecl; struct ZigClangPointerType; struct ZigClangPreprocessedEntity; -struct ZigClangQualType; struct ZigClangRecordDecl; struct ZigClangRecordType; struct ZigClangReturnStmt; @@ -246,4 +249,11 @@ ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigCla ZigClangSourceLocation Loc); ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *, ZigClangSourceLocation SL); + +ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T); + +ZIG_EXTERN_C ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *); +ZIG_EXTERN_C ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *); +ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *, void *context, + bool (*Fn)(void *context, const ZigClangDecl *decl)); #endif From fd61a084e49037bc53dd5150bd27e28758b7aecf Mon Sep 17 00:00:00 2001 From: sjdh02 Date: Fri, 25 Jan 2019 03:02:06 +0000 Subject: [PATCH 216/218] fix BufferedInStream not reading delayed input --- std/io.zig | 70 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/std/io.zig b/std/io.zig index 6c70834b52..2afd54cadd 100644 --- a/std/io.zig +++ b/std/io.zig @@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) const amt_buffered = self.end_index - self.start_index; if (amt_buffered == 0) { assert(self.end_index <= buffer_size); - if (self.end_index == buffer_size) { - // we can read more data from the unbuffered stream - if (dest_space < buffer_size) { - self.start_index = 0; - self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); - } else { - // asking for so much data that buffering is actually less efficient. - // forward the request directly to the unbuffered stream - const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); - return dest_index + amt_read; - } - } else { - // reading from the unbuffered stream returned less than we asked for - // so we cannot read any more data. + // Make sure the last read actually gave us some data + if (self.end_index == 0) { + // reading from the unbuffered stream returned nothing + // so we have nothing left to read. return dest_index; } + // we can read more data from the unbuffered stream + if (dest_space < buffer_size) { + self.start_index = 0; + self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); + } else { + // asking for so much data that buffering is actually less efficient. + // forward the request directly to the unbuffered stream + const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); + return dest_index + amt_read; + } } + const copy_amount = math.min(dest_space, amt_buffered); const copy_end_index = self.start_index + copy_amount; mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); @@ -370,6 +371,46 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) }; } +test "io.BufferedInStream" { + const OneByteReadInStream = struct { + const Error = error{NoError}; + const Stream = InStream(Error); + + stream: Stream, + str: []const u8, + curr: usize, + + fn init(str: []const u8) @This() { + return @This(){ + .stream = Stream{ .readFn = readFn }, + .str = str, + .curr = 0, + }; + } + + fn readFn(in_stream: *Stream, dest: []u8) Error!usize { + const self = @fieldParentPtr(@This(), "stream", in_stream); + if (self.str.len <= self.curr or dest.len == 0) + return 0; + + dest[0] = self.str[self.curr]; + self.curr += 1; + return 1; + } + }; + + var buf: [100]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + + const str = "This is a test"; + var one_byte_stream = OneByteReadInStream.init(str); + var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream); + const stream = &buf_in_stream.stream; + + const res = try stream.readAllAlloc(allocator, str.len + 1); + debug.assertOrPanic(mem.eql(u8, str, res)); +} + /// Creates a stream which supports 'un-reading' data, so that it can be read again. /// This makes look-ahead style parsing much easier. pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { @@ -1411,3 +1452,4 @@ test "import io tests" { _ = @import("io_test.zig"); } } + From 4a0bb6258406aa1f4f876116d47be6b93e115e23 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Feb 2019 22:47:58 -0500 Subject: [PATCH 217/218] fixups --- std/io.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/io.zig b/std/io.zig index 2afd54cadd..f6e3790af6 100644 --- a/std/io.zig +++ b/std/io.zig @@ -408,7 +408,7 @@ test "io.BufferedInStream" { const stream = &buf_in_stream.stream; const res = try stream.readAllAlloc(allocator, str.len + 1); - debug.assertOrPanic(mem.eql(u8, str, res)); + testing.expectEqualSlices(u8, str, res); } /// Creates a stream which supports 'un-reading' data, so that it can be read again. From 8d2a902945ef97f28152c3d5a68bb974809c8539 Mon Sep 17 00:00:00 2001 From: Maya Rashish Date: Sun, 17 Feb 2019 08:34:20 +0200 Subject: [PATCH 218/218] freebsd: fix pointer cast in mmap --- std/os/freebsd/index.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index a3ab5e7749..48c0ea5b1e 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -617,7 +617,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize { 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), + @ptrCast(?*c_void, address), length, @bitCast(c_int, @intCast(c_uint, prot)), @bitCast(c_int, c_uint(flags)),