aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig29
-rw-r--r--doc/build.zig.zon.md7
-rw-r--r--doc/langref.html.in10
-rw-r--r--lib/docs/wasm/markdown/Parser.zig2
-rw-r--r--lib/init/build.zig8
-rw-r--r--lib/init/build.zig.zon5
-rw-r--r--lib/std/Build.zig117
-rw-r--r--lib/std/Build/Module.zig15
-rw-r--r--lib/std/Build/Step/CheckObject.zig120
-rw-r--r--lib/std/Build/Step/Compile.zig41
-rw-r--r--lib/std/Build/Step/ConfigHeader.zig13
-rw-r--r--lib/std/Target.zig7
-rw-r--r--lib/std/Uri.zig644
-rw-r--r--lib/std/c/haiku.zig1305
-rw-r--r--lib/std/crypto/Certificate.zig2
-rw-r--r--lib/std/crypto/benchmark.zig7
-rw-r--r--lib/std/crypto/ecdsa.zig21
-rw-r--r--lib/std/crypto/keccak_p.zig25
-rw-r--r--lib/std/crypto/pcurves/p256/p256_64.zig18
-rw-r--r--lib/std/crypto/pcurves/p256/p256_scalar_64.zig18
-rw-r--r--lib/std/crypto/pcurves/p384/p384_64.zig18
-rw-r--r--lib/std/crypto/pcurves/p384/p384_scalar_64.zig18
-rw-r--r--lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig18
-rw-r--r--lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig18
-rw-r--r--lib/std/crypto/sha3.zig461
-rw-r--r--lib/std/debug.zig4
-rw-r--r--lib/std/fs/Dir.zig159
-rw-r--r--lib/std/hash/crc.zig1180
-rw-r--r--lib/std/hash/crc/catalog.zig903
-rw-r--r--lib/std/hash/crc/impl.zig241
-rw-r--r--lib/std/hash/crc/test.zig (renamed from lib/std/hash/crc/catalog_test.zig)245
-rw-r--r--lib/std/http/Client.zig239
-rw-r--r--lib/std/http/test.zig72
-rw-r--r--lib/std/io.zig2
-rw-r--r--lib/std/math/big/int.zig12
-rw-r--r--lib/std/math/big/int_test.zig13
-rw-r--r--lib/std/once.zig6
-rw-r--r--lib/std/posix/test.zig2
-rw-r--r--lib/std/tar.zig17
-rw-r--r--lib/std/zig/Zir.zig8
-rw-r--r--lib/std/zig/system.zig10
-rw-r--r--lib/std/zig/system/NativePaths.zig7
-rw-r--r--src/Compilation.zig21
-rw-r--r--src/InternPool.zig354
-rw-r--r--src/Module.zig113
-rw-r--r--src/Package.zig4
-rw-r--r--src/Package/Fetch.zig615
-rw-r--r--src/Package/Fetch/git.zig57
-rw-r--r--src/Package/Fetch/testdata/duplicate_paths.tar.gzbin0 -> 3230 bytes
-rw-r--r--src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gzbin0 -> 3237 bytes
-rw-r--r--src/Package/Fetch/testdata/executables.tar.gzbin0 -> 430 bytes
-rw-r--r--src/Package/Fetch/testdata/no_root.tar.gzbin0 -> 3172 bytes
-rw-r--r--src/Sema.zig581
-rw-r--r--src/Value.zig180
-rw-r--r--src/arch/aarch64/CodeGen.zig4
-rw-r--r--src/arch/wasm/CodeGen.zig19
-rw-r--r--src/arch/x86_64/CodeGen.zig6
-rw-r--r--src/codegen.zig107
-rw-r--r--src/codegen/c.zig1701
-rw-r--r--src/codegen/c/Type.zig338
-rw-r--r--src/codegen/llvm.zig113
-rw-r--r--src/codegen/spirv.zig43
-rw-r--r--src/link/Coff.zig48
-rw-r--r--src/link/Dwarf.zig37
-rw-r--r--src/link/Elf.zig29
-rw-r--r--src/link/Elf/Atom.zig4
-rw-r--r--src/link/Elf/Object.zig2
-rw-r--r--src/link/Elf/Symbol.zig24
-rw-r--r--src/link/Elf/ZigObject.zig34
-rw-r--r--src/link/Elf/synthetic_sections.zig24
-rw-r--r--src/link/MachO/ZigObject.zig38
-rw-r--r--src/link/Plan9.zig42
-rw-r--r--src/link/SpirV.zig24
-rw-r--r--src/link/Wasm/ZigObject.zig48
-rw-r--r--src/mutable_value.zig12
-rw-r--r--src/print_value.zig49
-rw-r--r--src/target.zig13
-rw-r--r--src/translate_c.zig12
-rw-r--r--src/type.zig22
-rw-r--r--stage1/zig1.wasmbin2780069 -> 2770790 bytes
-rw-r--r--test/behavior/abs.zig2
-rw-r--r--test/behavior/call.zig8
-rw-r--r--test/behavior/call_tail.zig3
-rw-r--r--test/behavior/cast.zig3
-rw-r--r--test/behavior/export_builtin.zig3
-rw-r--r--test/behavior/extern.zig2
-rw-r--r--test/behavior/fn.zig1
-rw-r--r--test/behavior/globals.zig3
-rw-r--r--test/behavior/optional.zig58
-rw-r--r--test/behavior/packed-struct.zig3
-rw-r--r--test/behavior/undefined.zig1
-rw-r--r--test/behavior/union.zig1
-rw-r--r--test/behavior/vector.zig1
-rw-r--r--test/cases/translate_c/assert_with_strlit.c8
-rw-r--r--test/cases/translate_c/strlit_as_bool.c8
-rw-r--r--test/link/bss/build.zig2
-rw-r--r--test/link/common_symbols/build.zig2
-rw-r--r--test/link/common_symbols_alignment/build.zig2
-rw-r--r--test/link/glibc_compat/build.zig4
-rw-r--r--test/link/interdependent_static_c_libs/build.zig12
-rw-r--r--test/link/macho.zig6
-rw-r--r--test/link/static_libs_from_object_files/build.zig6
-rw-r--r--test/link/wasm/archive/build.zig2
-rw-r--r--test/link/wasm/basic-features/build.zig2
-rw-r--r--test/link/wasm/bss/build.zig4
-rw-r--r--test/link/wasm/export-data/build.zig2
-rw-r--r--test/link/wasm/export/build.zig6
-rw-r--r--test/link/wasm/extern-mangle/build.zig2
-rw-r--r--test/link/wasm/extern/build.zig4
-rw-r--r--test/link/wasm/function-table/build.zig6
-rw-r--r--test/link/wasm/infer-features/build.zig4
-rw-r--r--test/link/wasm/producers/build.zig2
-rw-r--r--test/link/wasm/segments/build.zig2
-rw-r--r--test/link/wasm/shared-memory/build.zig2
-rw-r--r--test/link/wasm/stack_pointer/build.zig2
-rw-r--r--test/link/wasm/type/build.zig2
-rw-r--r--test/standalone/build.zig2
-rw-r--r--test/standalone/c_compiler/build.zig4
-rw-r--r--test/standalone/child_process/build.zig4
-rw-r--r--test/standalone/cmakedefine/build.zig10
-rw-r--r--test/standalone/compiler_rt_panic/build.zig2
-rw-r--r--test/standalone/dep_diamond/build.zig8
-rw-r--r--test/standalone/dep_mutually_recursive/build.zig6
-rw-r--r--test/standalone/dep_recursive/build.zig4
-rw-r--r--test/standalone/dep_shared_builtin/build.zig4
-rw-r--r--test/standalone/dep_triangle/build.zig6
-rw-r--r--test/standalone/depend_on_main_mod/build.zig4
-rw-r--r--test/standalone/dirname/build.zig8
-rw-r--r--test/standalone/embed_generated_file/build.zig4
-rw-r--r--test/standalone/empty_env/build.zig2
-rw-r--r--test/standalone/extern/build.zig4
-rw-r--r--test/standalone/global_linkage/build.zig6
-rw-r--r--test/standalone/install_headers/build.zig4
-rw-r--r--test/standalone/install_raw_hex/build.zig2
-rw-r--r--test/standalone/ios/build.zig8
-rw-r--r--test/standalone/issue_11595/build.zig2
-rw-r--r--test/standalone/issue_12706/build.zig2
-rw-r--r--test/standalone/issue_339/build.zig2
-rw-r--r--test/standalone/issue_794/build.zig4
-rw-r--r--test/standalone/issue_8550/build.zig6
-rw-r--r--test/standalone/load_dynamic_library/build.zig4
-rw-r--r--test/standalone/mix_c_files/build.zig4
-rw-r--r--test/standalone/mix_o_files/build.zig4
-rw-r--r--test/standalone/pie/build.zig2
-rw-r--r--test/standalone/pkg_import/build.zig4
-rw-r--r--test/standalone/self_exe_symlink/build.zig4
-rw-r--r--test/standalone/shared_library/build.zig4
-rw-r--r--test/standalone/simple/build.zig4
-rw-r--r--test/standalone/stack_iterator/build.zig8
-rw-r--r--test/standalone/static_c_lib/build.zig8
-rw-r--r--test/standalone/strip_empty_loop/build.zig2
-rw-r--r--test/standalone/strip_struct_init/build.zig2
-rw-r--r--test/standalone/test_runner_module_imports/build.zig8
-rw-r--r--test/standalone/test_runner_path/build.zig4
-rw-r--r--test/standalone/use_alias/build.zig4
-rw-r--r--test/standalone/windows_entry_points/build.zig8
-rw-r--r--test/standalone/windows_resources/build.zig4
-rw-r--r--test/standalone/zerolength_check/build.zig2
-rw-r--r--test/tests.zig40
-rw-r--r--tools/update_crc_catalog.zig49
160 files changed, 6411 insertions, 4832 deletions
diff --git a/build.zig b/build.zig
index 11d716a17f..0e43b82f9a 100644
--- a/build.zig
+++ b/build.zig
@@ -34,7 +34,7 @@ pub fn build(b: *std.Build) !void {
const docgen_exe = b.addExecutable(.{
.name = "docgen",
- .root_source_file = .{ .path = "tools/docgen.zig" },
+ .root_source_file = b.path("tools/docgen.zig"),
.target = b.host,
.optimize = .Debug,
.single_threaded = single_threaded,
@@ -46,7 +46,7 @@ pub fn build(b: *std.Build) !void {
docgen_cmd.addArg("--zig-lib-dir");
docgen_cmd.addDirectoryArg(p);
}
- docgen_cmd.addFileArg(.{ .path = "doc/langref.html.in" });
+ docgen_cmd.addFileArg(b.path("doc/langref.html.in"));
const langref_file = docgen_cmd.addOutputFileArg("langref.html");
const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html");
if (!skip_install_langref) {
@@ -55,9 +55,9 @@ pub fn build(b: *std.Build) !void {
const autodoc_test = b.addObject(.{
.name = "std",
- .root_source_file = .{ .path = "lib/std/std.zig" },
+ .root_source_file = b.path("lib/std/std.zig"),
.target = target,
- .zig_lib_dir = .{ .path = "lib" },
+ .zig_lib_dir = b.path("lib"),
.optimize = .Debug,
});
const install_std_docs = b.addInstallDirectory(.{
@@ -86,7 +86,7 @@ pub fn build(b: *std.Build) !void {
const check_case_exe = b.addExecutable(.{
.name = "check-case",
- .root_source_file = .{ .path = "test/src/Cases.zig" },
+ .root_source_file = b.path("test/src/Cases.zig"),
.target = b.host,
.optimize = optimize,
.single_threaded = single_threaded,
@@ -135,7 +135,7 @@ pub fn build(b: *std.Build) !void {
if (!skip_install_lib_files) {
b.installDirectory(.{
- .source_dir = .{ .path = "lib" },
+ .source_dir = b.path("lib"),
.install_dir = if (flat) .prefix else .lib,
.install_subdir = if (flat) "lib" else "zig",
.exclude_extensions = &[_][]const u8{
@@ -552,10 +552,10 @@ pub fn build(b: *std.Build) !void {
const update_mingw_exe = b.addExecutable(.{
.name = "update_mingw",
.target = b.host,
- .root_source_file = .{ .path = "tools/update_mingw.zig" },
+ .root_source_file = b.path("tools/update_mingw.zig"),
});
const update_mingw_run = b.addRunArtifact(update_mingw_exe);
- update_mingw_run.addDirectoryArg(.{ .path = "lib" });
+ update_mingw_run.addDirectoryArg(b.path("lib"));
if (opt_mingw_src_path) |mingw_src_path| {
update_mingw_run.addDirectoryArg(.{ .cwd_relative = mingw_src_path });
} else {
@@ -606,10 +606,10 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
});
run_opt.addArtifactArg(exe);
run_opt.addArg("-o");
- run_opt.addFileArg(.{ .path = "stage1/zig1.wasm" });
+ run_opt.addFileArg(b.path("stage1/zig1.wasm"));
const copy_zig_h = b.addWriteFiles();
- copy_zig_h.addCopyFileToSource(.{ .path = "lib/zig.h" }, "stage1/zig.h");
+ copy_zig_h.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h");
const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm");
update_zig1_step.dependOn(&run_opt.step);
@@ -627,7 +627,7 @@ const AddCompilerStepOptions = struct {
fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.Step.Compile {
const exe = b.addExecutable(.{
.name = "zig",
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = options.target,
.optimize = options.optimize,
.max_rss = 7_000_000_000,
@@ -638,11 +638,11 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St
exe.stack_size = stack_size;
const aro_module = b.createModule(.{
- .root_source_file = .{ .path = "lib/compiler/aro/aro.zig" },
+ .root_source_file = b.path("lib/compiler/aro/aro.zig"),
});
const aro_translate_c_module = b.createModule(.{
- .root_source_file = .{ .path = "lib/compiler/aro_translate_c.zig" },
+ .root_source_file = b.path("lib/compiler/aro_translate_c.zig"),
.imports = &.{
.{
.name = "aro",
@@ -747,6 +747,9 @@ fn addCmakeCfgOptionsToExe(
try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
},
+ .haiku => {
+ try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
+ },
else => {},
}
}
diff --git a/doc/build.zig.zon.md b/doc/build.zig.zon.md
index ad2ff61b64..de5ec5fe9c 100644
--- a/doc/build.zig.zon.md
+++ b/doc/build.zig.zon.md
@@ -63,6 +63,13 @@ When this is provided, the package is found in a directory relative to the
build root. In this case the package's hash is irrelevant and therefore not
computed. This field and `url` are mutually exclusive.
+#### `lazy`
+
+Boolean.
+
+When this is set to `true`, a package is declared to be lazily fetched. This
+makes the dependency only get fetched if it is actually used.
+
### `paths`
List. Required.
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 1d1468ab95..6f3e9961c3 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -3323,6 +3323,16 @@ fn doTheTest() !void {
}
{#code_end#}
<p>
+ The backing integer is inferred from the fields' total bit width.
+ Optionally, it can be explicitly provided and enforced at compile time:
+ </p>
+ {#code_begin|test_err|test_missized_packed_struct|backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 24#}
+test "missized packed struct" {
+ const S = packed struct(u32) { a: u16, b: u8 };
+ _ = S{ .a = 4, .b = 2 };
+}
+ {#code_end#}
+ <p>
Zig allows the address to be taken of a non-byte-aligned field:
</p>
{#code_begin|test|test_pointer_to_non-byte_aligned_field#}
diff --git a/lib/docs/wasm/markdown/Parser.zig b/lib/docs/wasm/markdown/Parser.zig
index 7f463224be..fe4fc2f9b0 100644
--- a/lib/docs/wasm/markdown/Parser.zig
+++ b/lib/docs/wasm/markdown/Parser.zig
@@ -1540,7 +1540,7 @@ const InlineParser = struct {
iter.pos += 1;
return .{ .text = replacement };
};
- const is_valid = iter.pos + cp_len < iter.content.len and
+ const is_valid = iter.pos + cp_len <= iter.content.len and
std.unicode.utf8ValidateSlice(iter.content[iter.pos..][0..cp_len]);
const cp_encoded = if (is_valid)
iter.content[iter.pos..][0..cp_len]
diff --git a/lib/init/build.zig b/lib/init/build.zig
index e513acdf25..d53cbbb982 100644
--- a/lib/init/build.zig
+++ b/lib/init/build.zig
@@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
.name = "$",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
- .root_source_file = .{ .path = "src/root.zig" },
+ .root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
@@ -31,7 +31,7 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "$",
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
@@ -67,7 +67,7 @@ pub fn build(b: *std.Build) void {
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const lib_unit_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/root.zig" },
+ .root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
@@ -75,7 +75,7 @@ pub fn build(b: *std.Build) void {
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
const exe_unit_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
diff --git a/lib/init/build.zig.zon b/lib/init/build.zig.zon
index dc9d138ba5..50da5587b1 100644
--- a/lib/init/build.zig.zon
+++ b/lib/init/build.zig.zon
@@ -37,6 +37,11 @@
// // build root. In this case the package's hash is irrelevant and therefore not
// // computed. This field and `url` are mutually exclusive.
// .path = "foo",
+
+ // // When this is set to `true`, a package is declared to be lazily
+ // // fetched. This makes the dependency only get fetched if it is
+ // // actually used.
+ // .lazy = false,
//},
},
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index 2c644ce4b0..a3d091858a 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -607,17 +607,17 @@ pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list:
var h_list = [_][]const u8{ self.install_path, "include" };
if (dir_list.lib_dir) |dir| {
- if (std.fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse "";
+ if (fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse "";
lib_list[1] = dir;
}
if (dir_list.exe_dir) |dir| {
- if (std.fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse "";
+ if (fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse "";
exe_list[1] = dir;
}
if (dir_list.include_dir) |dir| {
- if (std.fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse "";
+ if (fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse "";
h_list[1] = dir;
}
@@ -858,7 +858,7 @@ pub const TestOptions = struct {
/// deprecated: use `.filters = &.{filter}` instead of `.filter = filter`.
filter: ?[]const u8 = null,
filters: []const []const u8 = &.{},
- test_runner: ?[]const u8 = null,
+ test_runner: ?LazyPath = null,
link_libc: ?bool = null,
single_threaded: ?bool = null,
pic: ?bool = null,
@@ -1546,22 +1546,22 @@ pub fn addInstallArtifact(
}
///`dest_rel_path` is relative to prefix path
-pub fn installFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
- self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step);
+pub fn installFile(b: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(b.path(src_path), .prefix, dest_rel_path).step);
}
-pub fn installDirectory(self: *Build, options: Step.InstallDir.Options) void {
- self.getInstallStep().dependOn(&self.addInstallDirectory(options).step);
+pub fn installDirectory(b: *Build, options: Step.InstallDir.Options) void {
+ b.getInstallStep().dependOn(&b.addInstallDirectory(options).step);
}
///`dest_rel_path` is relative to bin path
-pub fn installBinFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
- self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step);
+pub fn installBinFile(b: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(b.path(src_path), .bin, dest_rel_path).step);
}
///`dest_rel_path` is relative to lib path
-pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
- self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
+pub fn installLibFile(b: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(b.path(src_path), .lib, dest_rel_path).step);
}
pub fn addObjCopy(b: *Build, source: LazyPath, options: Step.ObjCopy.Options) *Step.ObjCopy {
@@ -1635,6 +1635,22 @@ pub fn truncateFile(self: *Build, dest_path: []const u8) !void {
src_file.close();
}
+/// References a file or directory relative to the source root.
+pub fn path(b: *Build, sub_path: []const u8) LazyPath {
+ if (fs.path.isAbsolute(sub_path)) {
+ std.debug.panic("sub_path is expected to be relative to the build root, but was this absolute path: '{s}'. It is best avoid absolute paths, but if you must, it is supported by LazyPath.cwd_relative", .{
+ sub_path,
+ });
+ }
+ return .{ .src_path = .{
+ .owner = b,
+ .sub_path = sub_path,
+ } };
+}
+
+/// This is low-level implementation details of the build system, not meant to
+/// be called by users' build scripts. Even in the build system itself it is a
+/// code smell to call this function.
pub fn pathFromRoot(b: *Build, p: []const u8) []u8 {
return fs.path.resolve(b.allocator, &.{ b.build_root.path orelse ".", p }) catch @panic("OOM");
}
@@ -1674,10 +1690,9 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con
return name;
}
var it = mem.tokenizeScalar(u8, PATH, fs.path.delimiter);
- while (it.next()) |path| {
+ while (it.next()) |p| {
const full_path = self.pathJoin(&.{
- path,
- self.fmt("{s}{s}", .{ name, exe_extension }),
+ p, self.fmt("{s}{s}", .{ name, exe_extension }),
});
return fs.realpathAlloc(self.allocator, full_path) catch continue;
}
@@ -1687,10 +1702,9 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con
if (fs.path.isAbsolute(name)) {
return name;
}
- for (paths) |path| {
+ for (paths) |p| {
const full_path = self.pathJoin(&.{
- path,
- self.fmt("{s}{s}", .{ name, exe_extension }),
+ p, self.fmt("{s}{s}", .{ name, exe_extension }),
});
return fs.realpathAlloc(self.allocator, full_path) catch continue;
}
@@ -1771,7 +1785,7 @@ pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8)
.bin => self.exe_dir,
.lib => self.lib_dir,
.header => self.h_dir,
- .custom => |path| self.pathJoin(&.{ self.install_path, path }),
+ .custom => |p| self.pathJoin(&.{ self.install_path, p }),
};
return fs.path.resolve(
self.allocator,
@@ -2032,7 +2046,7 @@ fn dependencyInner(
const build_root: std.Build.Cache.Directory = .{
.path = build_root_string,
- .handle = std.fs.cwd().openDir(build_root_string, .{}) catch |err| {
+ .handle = fs.cwd().openDir(build_root_string, .{}) catch |err| {
std.debug.print("unable to open '{s}': {s}\n", .{
build_root_string, @errorName(err),
});
@@ -2093,9 +2107,9 @@ pub const GeneratedFile = struct {
// so that we can join it with another path (e.g. build root, cache root, etc.)
//
// dirname("") should still be null, because we can't go up any further.
-fn dirnameAllowEmpty(path: []const u8) ?[]const u8 {
- return fs.path.dirname(path) orelse {
- if (fs.path.isAbsolute(path) or path.len == 0) return null;
+fn dirnameAllowEmpty(full_path: []const u8) ?[]const u8 {
+ return fs.path.dirname(full_path) orelse {
+ if (fs.path.isAbsolute(full_path) or full_path.len == 0) return null;
return "";
};
@@ -2117,11 +2131,15 @@ test dirnameAllowEmpty {
/// A reference to an existing or future path.
pub const LazyPath = union(enum) {
- /// A source file path relative to build root.
- /// This should not be an absolute path, but in an older iteration of the zig build
- /// system API, it was allowed to be absolute. Absolute paths should use `cwd_relative`.
+ /// Deprecated; use the `path` function instead.
path: []const u8,
+ /// A source file path relative to build root.
+ src_path: struct {
+ owner: *std.Build,
+ sub_path: []const u8,
+ },
+
/// A file that is generated by an interface. Those files usually are
/// not available until built by a build step.
generated: *const GeneratedFile,
@@ -2150,11 +2168,10 @@ pub const LazyPath = union(enum) {
sub_path: []const u8,
},
- /// Returns a new file source that will have a relative path to the build root guaranteed.
- /// Asserts the parameter is not an absolute path.
- pub fn relative(path: []const u8) LazyPath {
- std.debug.assert(!std.fs.path.isAbsolute(path));
- return LazyPath{ .path = path };
+ /// Deprecated. Call `path` instead.
+ pub fn relative(p: []const u8) LazyPath {
+ std.log.warn("deprecated. call std.Build.path instead", .{});
+ return .{ .path = p };
}
/// Returns a lazy path referring to the directory containing this path.
@@ -2168,13 +2185,16 @@ pub const LazyPath = union(enum) {
return switch (self) {
.generated => |gen| .{ .generated_dirname = .{ .generated = gen, .up = 0 } },
.generated_dirname => |gen| .{ .generated_dirname = .{ .generated = gen.generated, .up = gen.up + 1 } },
+ .src_path => |sp| .{ .src_path = .{
+ .owner = sp.owner,
+ .sub_path = dirnameAllowEmpty(sp.sub_path) orelse {
+ dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the build root\n", .{}) catch {};
+ @panic("misconfigured build script");
+ },
+ } },
.path => |p| .{
.path = dirnameAllowEmpty(p) orelse {
- dumpBadDirnameHelp(null, null,
- \\dirname() attempted to traverse outside the build root.
- \\This is not allowed.
- \\
- , .{}) catch {};
+ dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the build root\n", .{}) catch {};
@panic("misconfigured build script");
},
},
@@ -2195,7 +2215,6 @@ pub const LazyPath = union(enum) {
} else {
dumpBadDirnameHelp(null, null,
\\dirname() attempted to traverse outside the current working directory.
- \\This is not allowed.
\\
, .{}) catch {};
@panic("misconfigured build script");
@@ -2207,7 +2226,6 @@ pub const LazyPath = union(enum) {
.sub_path = dirnameAllowEmpty(dep.sub_path) orelse {
dumpBadDirnameHelp(null, null,
\\dirname() attempted to traverse outside the dependency root.
- \\This is not allowed.
\\
, .{}) catch {};
@panic("misconfigured build script");
@@ -2220,7 +2238,8 @@ pub const LazyPath = union(enum) {
/// Either returns the path or `"generated"`.
pub fn getDisplayName(self: LazyPath) []const u8 {
return switch (self) {
- .path, .cwd_relative => self.path,
+ .src_path => |sp| sp.sub_path,
+ .path, .cwd_relative => |p| p,
.generated => "generated",
.generated_dirname => "generated",
.dependency => "dependency",
@@ -2230,7 +2249,7 @@ pub const LazyPath = union(enum) {
/// Adds dependencies this file source implies to the given step.
pub fn addStepDependencies(self: LazyPath, other_step: *Step) void {
switch (self) {
- .path, .cwd_relative, .dependency => {},
+ .src_path, .path, .cwd_relative, .dependency => {},
.generated => |gen| other_step.dependOn(gen.step),
.generated_dirname => |gen| other_step.dependOn(gen.generated.step),
}
@@ -2250,6 +2269,7 @@ pub const LazyPath = union(enum) {
pub fn getPath2(self: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
switch (self) {
.path => |p| return src_builder.pathFromRoot(p),
+ .src_path => |sp| return sp.owner.pathFromRoot(sp.sub_path),
.cwd_relative => |p| return src_builder.pathFromCwd(p),
.generated => |gen| return gen.path orelse {
std.debug.getStderrMutex().lock();
@@ -2262,13 +2282,13 @@ pub const LazyPath = union(enum) {
(src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));
const gen_step = gen.generated.step;
- var path = getPath2(LazyPath{ .generated = gen.generated }, src_builder, asking_step);
+ var p = getPath2(LazyPath{ .generated = gen.generated }, src_builder, asking_step);
var i: usize = 0;
while (i <= gen.up) : (i += 1) {
// path is absolute.
// dirname will return null only if we're at root.
// Typically, we'll stop well before that at the cache root.
- path = fs.path.dirname(path) orelse {
+ p = fs.path.dirname(p) orelse {
dumpBadDirnameHelp(gen_step, asking_step,
\\dirname() reached root.
\\No more directories left to go up.
@@ -2277,7 +2297,7 @@ pub const LazyPath = union(enum) {
@panic("misconfigured build script");
};
- if (mem.eql(u8, path, cache_root_path) and i < gen.up) {
+ if (mem.eql(u8, p, cache_root_path) and i < gen.up) {
// If we hit the cache root and there's still more to go,
// the script attempted to go too far.
dumpBadDirnameHelp(gen_step, asking_step,
@@ -2288,7 +2308,7 @@ pub const LazyPath = union(enum) {
@panic("misconfigured build script");
}
}
- return path;
+ return p;
},
.dependency => |dep| {
return dep.dependency.builder.pathJoin(&[_][]const u8{
@@ -2299,9 +2319,16 @@ pub const LazyPath = union(enum) {
}
}
- /// Duplicates the file source for a given builder.
+ /// Copies the internal strings.
+ ///
+ /// The `b` parameter is only used for its allocator. All *Build instances
+ /// share the same allocator.
pub fn dupe(self: LazyPath, b: *Build) LazyPath {
return switch (self) {
+ .src_path => |sp| .{ .src_path = .{
+ .owner = sp.owner,
+ .sub_path = sp.owner.dupePath(sp.sub_path),
+ } },
.path => |p| .{ .path = b.dupePath(p) },
.cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) },
.generated => |gen| .{ .generated = gen },
diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig
index 02386de430..d19f0a781e 100644
--- a/lib/std/Build/Module.zig
+++ b/lib/std/Build/Module.zig
@@ -451,7 +451,7 @@ pub fn linkFramework(m: *Module, name: []const u8, options: LinkFrameworkOptions
pub const AddCSourceFilesOptions = struct {
/// When provided, `files` are relative to `root` rather than the
/// package that owns the `Compile` step.
- root: LazyPath = .{ .path = "" },
+ root: ?LazyPath = null,
files: []const []const u8,
flags: []const []const u8 = &.{},
};
@@ -472,7 +472,7 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void {
const c_source_files = allocator.create(CSourceFiles) catch @panic("OOM");
c_source_files.* = .{
- .root = options.root,
+ .root = options.root orelse b.path(""),
.files = b.dupeStrings(options.files),
.flags = b.dupeStrings(options.flags),
};
@@ -573,17 +573,6 @@ pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void {
pub fn addRPath(m: *Module, directory_path: LazyPath) void {
const b = m.owner;
- switch (directory_path) {
- .path, .cwd_relative => |path| {
- // TODO: remove this check after people upgrade and stop expecting it to work
- if (std.mem.startsWith(u8, path, "@executable_path") or
- std.mem.startsWith(u8, path, "@loader_path"))
- {
- @panic("this function is for adding directory paths. It does not support special rpaths. use addRPathSpecial for that.");
- }
- },
- else => {},
- }
m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM");
addLazyPathDependenciesOnly(m, directory_path);
}
diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig
index c39a487649..f8f0fcd584 100644
--- a/lib/std/Build/Step/CheckObject.zig
+++ b/lib/std/Build/Step/CheckObject.zig
@@ -247,15 +247,27 @@ const ComputeCompareExpected = struct {
const Check = struct {
kind: Kind,
+ payload: Payload,
+ data: std.ArrayList(u8),
actions: std.ArrayList(Action),
fn create(allocator: Allocator, kind: Kind) Check {
return .{
.kind = kind,
+ .payload = .{ .none = {} },
+ .data = std.ArrayList(u8).init(allocator),
.actions = std.ArrayList(Action).init(allocator),
};
}
+ fn dumpSection(allocator: Allocator, name: [:0]const u8) Check {
+ var check = Check.create(allocator, .dump_section);
+ const off: u32 = @intCast(check.data.items.len);
+ check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM");
+ check.payload = .{ .dump_section = off };
+ return check;
+ }
+
fn extract(self: *Check, phrase: SearchPhrase) void {
self.actions.append(.{
.tag = .extract,
@@ -305,6 +317,13 @@ const Check = struct {
dyld_lazy_bind,
exports,
compute_compare,
+ dump_section,
+ };
+
+ const Payload = union {
+ none: void,
+ /// Null-delimited string in the 'data' buffer.
+ dump_section: u32,
};
};
@@ -513,6 +532,11 @@ pub fn checkInArchiveSymtab(self: *CheckObject) void {
self.checkExact(label);
}
+pub fn dumpSection(self: *CheckObject, name: [:0]const u8) void {
+ const new_check = Check.dumpSection(self.step.owner.allocator, name);
+ self.checks.append(new_check) catch @panic("OOM");
+}
+
/// Creates a new standalone, singular check which allows running simple binary operations
/// on the extracted variables. It will then compare the reduced program with the value of
/// the expected variable.
@@ -564,13 +588,44 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
const output = switch (self.obj_format) {
- .macho => try MachODumper.parseAndDump(step, chk.kind, contents),
- .elf => try ElfDumper.parseAndDump(step, chk.kind, contents),
+ .macho => try MachODumper.parseAndDump(step, chk, contents),
+ .elf => try ElfDumper.parseAndDump(step, chk, contents),
.coff => return step.fail("TODO coff parser", .{}),
- .wasm => try WasmDumper.parseAndDump(step, chk.kind, contents),
+ .wasm => try WasmDumper.parseAndDump(step, chk, contents),
else => unreachable,
};
+ // Depending on whether we requested dumping section verbatim or not,
+ // we either format message string with escaped codes, or not to aid debugging
+ // the failed test.
+ const fmtMessageString = struct {
+ fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(formatMessageString) {
+ return .{ .data = .{
+ .kind = kind,
+ .msg = msg,
+ } };
+ }
+
+ const Ctx = struct {
+ kind: Check.Kind,
+ msg: []const u8,
+ };
+
+ fn formatMessageString(
+ ctx: Ctx,
+ comptime unused_fmt_string: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+ ) !void {
+ _ = unused_fmt_string;
+ _ = options;
+ switch (ctx.kind) {
+ .dump_section => try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ctx.msg)}),
+ else => try writer.writeAll(ctx.msg),
+ }
+ }
+ }.fmtMessageString;
+
var it = mem.tokenizeAny(u8, output, "\r\n");
for (chk.actions.items) |act| {
switch (act.tag) {
@@ -585,7 +640,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does not contain it: =======
\\{s}
\\======================================================
- , .{ act.phrase.resolve(b, step), output });
+ , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
}
},
@@ -600,7 +655,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does not contain it: =======
\\{s}
\\======================================================
- , .{ act.phrase.resolve(b, step), output });
+ , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
}
},
@@ -614,7 +669,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does contain it: ========
\\{s}
\\===================================================
- , .{ act.phrase.resolve(b, step), output });
+ , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
}
},
@@ -629,7 +684,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
\\========= but parsed file does not contain it: =======
\\{s}
\\======================================================
- , .{ act.phrase.resolve(b, step), output });
+ , .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) });
}
},
@@ -660,7 +715,7 @@ const MachODumper = struct {
}
};
- fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
+ fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
const gpa = step.owner.allocator;
var stream = std.io.fixedBufferStream(bytes);
const reader = stream.reader();
@@ -731,7 +786,7 @@ const MachODumper = struct {
}
}
- switch (kind) {
+ switch (check.kind) {
.headers => {
try dumpHeader(hdr, writer);
@@ -764,7 +819,7 @@ const MachODumper = struct {
if (dyld_info_lc == null) return step.fail("no dyld info found", .{});
const lc = dyld_info_lc.?;
- switch (kind) {
+ switch (check.kind) {
.dyld_rebase => if (lc.rebase_size > 0) {
const data = bytes[lc.rebase_off..][0..lc.rebase_size];
try writer.writeAll(dyld_rebase_label ++ "\n");
@@ -805,7 +860,7 @@ const MachODumper = struct {
return step.fail("no exports data found", .{});
},
- else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}),
+ else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(check.kind)}),
}
return output.toOwnedSlice();
@@ -1633,14 +1688,14 @@ const ElfDumper = struct {
const dynamic_section_label = "dynamic section";
const archive_symtab_label = "archive symbol table";
- fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
- return parseAndDumpArchive(step, kind, bytes) catch |err| switch (err) {
- error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, kind, bytes),
+ fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
+ return parseAndDumpArchive(step, check, bytes) catch |err| switch (err) {
+ error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, check, bytes),
else => |e| return e,
};
}
- fn parseAndDumpArchive(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
+ fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
const gpa = step.owner.allocator;
var stream = std.io.fixedBufferStream(bytes);
const reader = stream.reader();
@@ -1702,13 +1757,13 @@ const ElfDumper = struct {
var output = std.ArrayList(u8).init(gpa);
const writer = output.writer();
- switch (kind) {
+ switch (check.kind) {
.archive_symtab => if (ctx.symtab.items.len > 0) {
try ctx.dumpSymtab(writer);
} else return step.fail("no archive symbol table found", .{}),
else => if (ctx.objects.items.len > 0) {
- try ctx.dumpObjects(step, kind, writer);
+ try ctx.dumpObjects(step, check, writer);
} else return step.fail("empty archive", .{}),
}
@@ -1785,10 +1840,10 @@ const ElfDumper = struct {
}
}
- fn dumpObjects(ctx: ArchiveContext, step: *Step, kind: Check.Kind, writer: anytype) !void {
+ fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, writer: anytype) !void {
for (ctx.objects.items) |object| {
try writer.print("object {s}\n", .{object.name});
- const output = try parseAndDumpObject(step, kind, ctx.data[object.off..][0..object.len]);
+ const output = try parseAndDumpObject(step, check, ctx.data[object.off..][0..object.len]);
defer ctx.gpa.free(output);
try writer.print("{s}\n", .{output});
}
@@ -1806,7 +1861,7 @@ const ElfDumper = struct {
};
};
- fn parseAndDumpObject(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
+ fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
const gpa = step.owner.allocator;
var stream = std.io.fixedBufferStream(bytes);
const reader = stream.reader();
@@ -1859,7 +1914,7 @@ const ElfDumper = struct {
var output = std.ArrayList(u8).init(gpa);
const writer = output.writer();
- switch (kind) {
+ switch (check.kind) {
.headers => {
try ctx.dumpHeader(writer);
try ctx.dumpShdrs(writer);
@@ -1878,7 +1933,13 @@ const ElfDumper = struct {
try ctx.dumpDynamicSection(shndx, writer);
} else return step.fail("no .dynamic section found", .{}),
- else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(kind)}),
+ .dump_section => {
+ const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0);
+ const shndx = ctx.getSectionByName(name) orelse return step.fail("no '{s}' section found", .{name});
+ try ctx.dumpSection(shndx, writer);
+ },
+
+ else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(check.kind)}),
}
return output.toOwnedSlice();
@@ -2176,6 +2237,11 @@ const ElfDumper = struct {
}
}
+ fn dumpSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void {
+ const data = ctx.getSectionContents(shndx);
+ try writer.print("{s}", .{data});
+ }
+
inline fn getSectionName(ctx: ObjectContext, shndx: usize) []const u8 {
const shdr = ctx.shdrs[shndx];
return getString(ctx.shstrtab, shdr.sh_name);
@@ -2300,7 +2366,7 @@ const ElfDumper = struct {
const WasmDumper = struct {
const symtab_label = "symbols";
- fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
+ fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
const gpa = step.owner.allocator;
var fbs = std.io.fixedBufferStream(bytes);
const reader = fbs.reader();
@@ -2317,7 +2383,7 @@ const WasmDumper = struct {
errdefer output.deinit();
const writer = output.writer();
- switch (kind) {
+ switch (check.kind) {
.headers => {
while (reader.readByte()) |current_byte| {
const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
@@ -2330,7 +2396,7 @@ const WasmDumper = struct {
} else |_| {} // reached end of stream
},
- else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(kind)}),
+ else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(check.kind)}),
}
return output.toOwnedSlice();
@@ -2364,7 +2430,7 @@ const WasmDumper = struct {
=> {
const entries = try std.leb.readULEB128(u32, reader);
try writer.print("\nentries {d}\n", .{entries});
- try dumpSection(step, section, data[fbs.pos..], entries, writer);
+ try parseSection(step, section, data[fbs.pos..], entries, writer);
},
.custom => {
const name_length = try std.leb.readULEB128(u32, reader);
@@ -2393,7 +2459,7 @@ const WasmDumper = struct {
}
}
- fn dumpSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void {
+ fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void {
var fbs = std.io.fixedBufferStream(data);
const reader = fbs.reader();
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index 4a5364176a..c36fd8c4ca 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -55,7 +55,7 @@ global_base: ?u64 = null,
zig_lib_dir: ?LazyPath,
exec_cmd_args: ?[]const ?[]const u8,
filters: []const []const u8,
-test_runner: ?[]const u8,
+test_runner: ?LazyPath,
test_server_mode: bool,
wasi_exec_model: ?std.builtin.WasiExecModel = null,
@@ -236,7 +236,7 @@ pub const Options = struct {
version: ?std.SemanticVersion = null,
max_rss: usize = 0,
filters: []const []const u8 = &.{},
- test_runner: ?[]const u8 = null,
+ test_runner: ?LazyPath = null,
use_llvm: ?bool = null,
use_lld: ?bool = null,
zig_lib_dir: ?LazyPath = null,
@@ -264,20 +264,8 @@ pub const HeaderInstallation = union(enum) {
dest_rel_path: []const u8,
pub fn dupe(self: File, b: *std.Build) File {
- // 'path' lazy paths are relative to the build root of some step, inferred from the step
- // in which they are used. This means that we can't dupe such paths, because they may
- // come from dependencies with their own build roots and duping the paths as is might
- // cause the build script to search for the file relative to the wrong root.
- // As a temporary workaround, we convert build root-relative paths to absolute paths.
- // If/when the build-root relative paths are updated to encode which build root they are
- // relative to, this workaround should be removed.
- const duped_source: LazyPath = switch (self.source) {
- .path => |root_rel| .{ .cwd_relative = b.pathFromRoot(root_rel) },
- else => self.source.dupe(b),
- };
-
return .{
- .source = duped_source,
+ .source = self.source.dupe(b),
.dest_rel_path = b.dupePath(self.dest_rel_path),
};
}
@@ -305,20 +293,8 @@ pub const HeaderInstallation = union(enum) {
};
pub fn dupe(self: Directory, b: *std.Build) Directory {
- // 'path' lazy paths are relative to the build root of some step, inferred from the step
- // in which they are used. This means that we can't dupe such paths, because they may
- // come from dependencies with their own build roots and duping the paths as is might
- // cause the build script to search for the file relative to the wrong root.
- // As a temporary workaround, we convert build root-relative paths to absolute paths.
- // If/when the build-root relative paths are updated to encode which build root they are
- // relative to, this workaround should be removed.
- const duped_source: LazyPath = switch (self.source) {
- .path => |root_rel| .{ .cwd_relative = b.pathFromRoot(root_rel) },
- else => self.source.dupe(b),
- };
-
return .{
- .source = duped_source,
+ .source = self.source.dupe(b),
.dest_rel_path = b.dupePath(self.dest_rel_path),
.options = self.options.dupe(b),
};
@@ -402,7 +378,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.zig_lib_dir = null,
.exec_cmd_args = null,
.filters = options.filters,
- .test_runner = options.test_runner,
+ .test_runner = null,
.test_server_mode = options.test_runner == null,
.rdynamic = false,
.installed_path = null,
@@ -429,6 +405,11 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
lp.addStepDependencies(&self.step);
}
+ if (options.test_runner) |lp| {
+ self.test_runner = lp.dupe(self.step.owner);
+ lp.addStepDependencies(&self.step);
+ }
+
// Only the PE/COFF format has a Resource Table which is where the manifest
// gets embedded, so for any other target the manifest file is just ignored.
if (target.ofmt == .coff) {
@@ -1402,7 +1383,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
if (self.test_runner) |test_runner| {
try zig_args.append("--test-runner");
- try zig_args.append(b.pathFromRoot(test_runner));
+ try zig_args.append(test_runner.getPath(b));
}
for (b.debug_log_scopes) |log_scope| {
diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig
index 46631cac24..e547f8082e 100644
--- a/lib/std/Build/Step/ConfigHeader.zig
+++ b/lib/std/Build/Step/ConfigHeader.zig
@@ -58,6 +58,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
if (options.style.getPath()) |s| default_include_path: {
const sub_path = switch (s) {
+ .src_path => |sp| sp.sub_path,
.path => |path| path,
.generated, .generated_dirname => break :default_include_path,
.cwd_relative => |sub_path| sub_path,
@@ -192,13 +193,21 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
.autoconf => |file_source| {
try output.appendSlice(c_generated_line);
const src_path = file_source.getPath(b);
- const contents = try std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes);
+ const contents = std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes) catch |err| {
+ return step.fail("unable to read autoconf input file '{s}': {s}", .{
+ src_path, @errorName(err),
+ });
+ };
try render_autoconf(step, contents, &output, self.values, src_path);
},
.cmake => |file_source| {
try output.appendSlice(c_generated_line);
const src_path = file_source.getPath(b);
- const contents = try std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes);
+ const contents = std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes) catch |err| {
+ return step.fail("unable to read cmake input file '{s}': {s}", .{
+ src_path, @errorName(err),
+ });
+ };
try render_cmake(step, contents, &output, self.values, src_path);
},
.blank => {
diff --git a/lib/std/Target.zig b/lib/std/Target.zig
index 842442e37b..55cde46308 100644
--- a/lib/std/Target.zig
+++ b/lib/std/Target.zig
@@ -2740,6 +2740,13 @@ pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
return true;
}
+ if (target.os.tag == .haiku) {
+ if (eqlIgnoreCase(ignore_case, name, "root"))
+ return true;
+ if (eqlIgnoreCase(ignore_case, name, "network"))
+ return true;
+ }
+
return false;
}
diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig
index cbd3d42741..ee0c602125 100644
--- a/lib/std/Uri.zig
+++ b/lib/std/Uri.zig
@@ -1,156 +1,157 @@
//! Uniform Resource Identifier (URI) parsing roughly adhering to <https://tools.ietf.org/html/rfc3986>.
//! Does not do perfect grammar and character class checking, but should be robust against URIs in the wild.
-const Uri = @This();
-const std = @import("std.zig");
-const testing = std.testing;
-const Allocator = std.mem.Allocator;
-
scheme: []const u8,
-user: ?[]const u8 = null,
-password: ?[]const u8 = null,
-host: ?[]const u8 = null,
+user: ?Component = null,
+password: ?Component = null,
+host: ?Component = null,
port: ?u16 = null,
-path: []const u8,
-query: ?[]const u8 = null,
-fragment: ?[]const u8 = null,
-
-/// Applies URI encoding and replaces all reserved characters with their respective %XX code.
-pub fn escapeString(allocator: Allocator, input: []const u8) error{OutOfMemory}![]u8 {
- return escapeStringWithFn(allocator, input, isUnreserved);
-}
-
-pub fn escapePath(allocator: Allocator, input: []const u8) error{OutOfMemory}![]u8 {
- return escapeStringWithFn(allocator, input, isPathChar);
-}
-
-pub fn escapeQuery(allocator: Allocator, input: []const u8) error{OutOfMemory}![]u8 {
- return escapeStringWithFn(allocator, input, isQueryChar);
-}
-
-pub fn writeEscapedString(writer: anytype, input: []const u8) !void {
- return writeEscapedStringWithFn(writer, input, isUnreserved);
-}
-
-pub fn writeEscapedPath(writer: anytype, input: []const u8) !void {
- return writeEscapedStringWithFn(writer, input, isPathChar);
-}
-
-pub fn writeEscapedQuery(writer: anytype, input: []const u8) !void {
- return writeEscapedStringWithFn(writer, input, isQueryChar);
-}
-
-pub fn escapeStringWithFn(allocator: Allocator, input: []const u8, comptime keepUnescaped: fn (c: u8) bool) Allocator.Error![]u8 {
- var outsize: usize = 0;
- for (input) |c| {
- outsize += if (keepUnescaped(c)) @as(usize, 1) else 3;
+path: Component = Component.empty,
+query: ?Component = null,
+fragment: ?Component = null,
+
+pub const Component = union(enum) {
+ /// Invalid characters in this component must be percent encoded
+ /// before being printed as part of a URI.
+ raw: []const u8,
+ /// This component is already percent-encoded, it can be printed
+ /// directly as part of a URI.
+ percent_encoded: []const u8,
+
+ pub const empty: Component = .{ .percent_encoded = "" };
+
+ pub fn isEmpty(component: Component) bool {
+ return switch (component) {
+ .raw, .percent_encoded => |string| string.len == 0,
+ };
}
- var output = try allocator.alloc(u8, outsize);
- var outptr: usize = 0;
- for (input) |c| {
- if (keepUnescaped(c)) {
- output[outptr] = c;
- outptr += 1;
- } else {
- var buf: [2]u8 = undefined;
- _ = std.fmt.bufPrint(&buf, "{X:0>2}", .{c}) catch unreachable;
-
- output[outptr + 0] = '%';
- output[outptr + 1] = buf[0];
- output[outptr + 2] = buf[1];
- outptr += 3;
- }
+ /// Allocates the result with `arena` only if needed, so the result should not be freed.
+ pub fn toRawMaybeAlloc(
+ component: Component,
+ arena: std.mem.Allocator,
+ ) std.mem.Allocator.Error![]const u8 {
+ return switch (component) {
+ .raw => |raw| raw,
+ .percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
+ try std.fmt.allocPrint(arena, "{raw}", .{component})
+ else
+ percent_encoded,
+ };
}
- return output;
-}
-pub fn writeEscapedStringWithFn(writer: anytype, input: []const u8, comptime keepUnescaped: fn (c: u8) bool) @TypeOf(writer).Error!void {
- for (input) |c| {
- if (keepUnescaped(c)) {
- try writer.writeByte(c);
- } else {
- try writer.print("%{X:0>2}", .{c});
- }
+ pub fn format(
+ component: Component,
+ comptime fmt_str: []const u8,
+ _: std.fmt.FormatOptions,
+ writer: anytype,
+ ) @TypeOf(writer).Error!void {
+ if (fmt_str.len == 0) {
+ try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
+ @tagName(component),
+ std.zig.fmtEscapes(switch (component) {
+ .raw, .percent_encoded => |string| string,
+ }),
+ });
+ } else if (comptime std.mem.eql(u8, fmt_str, "raw")) switch (component) {
+ .raw => |raw| try writer.writeAll(raw),
+ .percent_encoded => |percent_encoded| {
+ var start: usize = 0;
+ var index: usize = 0;
+ while (std.mem.indexOfScalarPos(u8, percent_encoded, index, '%')) |percent| {
+ index = percent + 1;
+ if (percent_encoded.len - index < 2) continue;
+ const percent_encoded_char =
+ std.fmt.parseInt(u8, percent_encoded[index..][0..2], 16) catch continue;
+ try writer.print("{s}{c}", .{
+ percent_encoded[start..percent],
+ percent_encoded_char,
+ });
+ start = percent + 3;
+ index = percent + 3;
+ }
+ try writer.writeAll(percent_encoded[start..]);
+ },
+ } else if (comptime std.mem.eql(u8, fmt_str, "%")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isUnreserved),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "user")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isUserChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "password")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isPasswordChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "host")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isHostChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "path")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isPathChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "query")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isQueryChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else if (comptime std.mem.eql(u8, fmt_str, "fragment")) switch (component) {
+ .raw => |raw| try percentEncode(writer, raw, isFragmentChar),
+ .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ } else @compileError("invalid format string '" ++ fmt_str ++ "'");
}
-}
-/// Parses a URI string and unescapes all %XX where XX is a valid hex number. Otherwise, verbatim copies
-/// them to the output.
-pub fn unescapeString(allocator: Allocator, input: []const u8) error{OutOfMemory}![]u8 {
- var outsize: usize = 0;
- var inptr: usize = 0;
- while (inptr < input.len) {
- if (input[inptr] == '%') {
- inptr += 1;
- if (inptr + 2 <= input.len) {
- _ = std.fmt.parseInt(u8, input[inptr..][0..2], 16) catch {
- outsize += 3;
- inptr += 2;
- continue;
- };
- inptr += 2;
- outsize += 1;
- } else {
- outsize += 1;
- }
- } else {
- inptr += 1;
- outsize += 1;
+ pub fn percentEncode(
+ writer: anytype,
+ raw: []const u8,
+ comptime isValidChar: fn (u8) bool,
+ ) @TypeOf(writer).Error!void {
+ var start: usize = 0;
+ for (raw, 0..) |char, index| {
+ if (isValidChar(char)) continue;
+ try writer.print("{s}%{X:0>2}", .{ raw[start..index], char });
+ start = index + 1;
}
+ try writer.writeAll(raw[start..]);
}
+};
- var output = try allocator.alloc(u8, outsize);
- var outptr: usize = 0;
- inptr = 0;
- while (inptr < input.len) {
- if (input[inptr] == '%') {
- inptr += 1;
- if (inptr + 2 <= input.len) {
- const value = std.fmt.parseInt(u8, input[inptr..][0..2], 16) catch {
- output[outptr + 0] = input[inptr + 0];
- output[outptr + 1] = input[inptr + 1];
- inptr += 2;
- outptr += 2;
+/// Percent decodes all %XX where XX is a valid hex number.
+/// `output` may alias `input` if `output.ptr <= input.ptr`.
+/// Mutates and returns a subslice of `output`.
+pub fn percentDecodeBackwards(output: []u8, input: []const u8) []u8 {
+ var input_index = input.len;
+ var output_index = output.len;
+ while (input_index > 0) {
+ if (input_index >= 3) {
+ const maybe_percent_encoded = input[input_index - 3 ..][0..3];
+ if (maybe_percent_encoded[0] == '%') {
+ if (std.fmt.parseInt(u8, maybe_percent_encoded[1..], 16)) |percent_encoded_char| {
+ input_index -= maybe_percent_encoded.len;
+ output_index -= 1;
+ output[output_index] = percent_encoded_char;
continue;
- };
-
- output[outptr] = value;
-
- inptr += 2;
- outptr += 1;
- } else {
- output[outptr] = input[inptr - 1];
- outptr += 1;
+ } else |_| {}
}
- } else {
- output[outptr] = input[inptr];
- inptr += 1;
- outptr += 1;
}
+ input_index -= 1;
+ output_index -= 1;
+ output[output_index] = input[input_index];
}
- return output;
+ return output[output_index..];
+}
+
+/// Percent decodes all %XX where XX is a valid hex number.
+/// Mutates and returns a subslice of `buffer`.
+pub fn percentDecodeInPlace(buffer: []u8) []u8 {
+ return percentDecodeBackwards(buffer, buffer);
}
pub const ParseError = error{ UnexpectedCharacter, InvalidFormat, InvalidPort };
/// Parses the URI or returns an error. This function is not compliant, but is required to parse
/// some forms of URIs in the wild, such as HTTP Location headers.
-/// The return value will contain unescaped strings pointing into the
-/// original `text`. Each component that is provided, will be non-`null`.
-pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
+/// The return value will contain strings pointing into the original `text`.
+/// Each component that is provided, will be non-`null`.
+pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri {
var reader = SliceReader{ .slice = text };
- var uri = Uri{
- .scheme = "",
- .user = null,
- .password = null,
- .host = null,
- .port = null,
- .path = "", // path is always set, but empty by default.
- .query = null,
- .fragment = null,
- };
+ var uri: Uri = .{ .scheme = scheme, .path = undefined };
if (reader.peekPrefix("//")) a: { // authority part
std.debug.assert(reader.get().? == '/');
@@ -167,12 +168,12 @@ pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
const user_info = authority[0..index];
if (std.mem.indexOf(u8, user_info, ":")) |idx| {
- uri.user = user_info[0..idx];
+ uri.user = .{ .percent_encoded = user_info[0..idx] };
if (idx < user_info.len - 1) { // empty password is also "no password"
- uri.password = user_info[idx + 1 ..];
+ uri.password = .{ .percent_encoded = user_info[idx + 1 ..] };
}
} else {
- uri.user = user_info;
+ uri.user = .{ .percent_encoded = user_info };
uri.password = null;
}
}
@@ -205,19 +206,19 @@ pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
}
if (start_of_host >= end_of_host) return error.InvalidFormat;
- uri.host = authority[start_of_host..end_of_host];
+ uri.host = .{ .percent_encoded = authority[start_of_host..end_of_host] };
}
- uri.path = reader.readUntil(isPathSeparator);
+ uri.path = .{ .percent_encoded = reader.readUntil(isPathSeparator) };
if ((reader.peek() orelse 0) == '?') { // query part
std.debug.assert(reader.get().? == '?');
- uri.query = reader.readUntil(isQuerySeparator);
+ uri.query = .{ .percent_encoded = reader.readUntil(isQuerySeparator) };
}
if ((reader.peek() orelse 0) == '#') { // fragment part
std.debug.assert(reader.get().? == '#');
- uri.fragment = reader.readUntilEof();
+ uri.fragment = .{ .percent_encoded = reader.readUntilEof() };
}
return uri;
@@ -242,8 +243,8 @@ pub const WriteToStreamOptions = struct {
/// When true, include the fragment part of the URI. Ignored when `path` is false.
fragment: bool = false,
- /// When true, do not escape any part of the URI.
- raw: bool = false,
+ /// When true, include the port part of the URI. Ignored when `port` is null.
+ port: bool = true,
};
pub fn writeToStream(
@@ -252,80 +253,53 @@ pub fn writeToStream(
writer: anytype,
) @TypeOf(writer).Error!void {
if (options.scheme) {
- try writer.writeAll(uri.scheme);
- try writer.writeAll(":");
-
+ try writer.print("{s}:", .{uri.scheme});
if (options.authority and uri.host != null) {
try writer.writeAll("//");
}
}
-
if (options.authority) {
if (options.authentication and uri.host != null) {
if (uri.user) |user| {
- try writer.writeAll(user);
+ try writer.print("{user}", .{user});
if (uri.password) |password| {
- try writer.writeAll(":");
- try writer.writeAll(password);
+ try writer.print(":{password}", .{password});
}
- try writer.writeAll("@");
+ try writer.writeByte('@');
}
}
-
if (uri.host) |host| {
- try writer.writeAll(host);
-
- if (uri.port) |port| {
- try writer.writeAll(":");
- try std.fmt.formatInt(port, 10, .lower, .{}, writer);
+ try writer.print("{host}", .{host});
+ if (options.port) {
+ if (uri.port) |port| try writer.print(":{d}", .{port});
}
}
}
-
if (options.path) {
- if (uri.path.len == 0) {
- try writer.writeAll("/");
- } else if (options.raw) {
- try writer.writeAll(uri.path);
- } else {
- try writeEscapedPath(writer, uri.path);
+ try writer.print("{path}", .{
+ if (uri.path.isEmpty()) Uri.Component{ .percent_encoded = "/" } else uri.path,
+ });
+ if (options.query) {
+ if (uri.query) |query| try writer.print("?{query}", .{query});
+ }
+ if (options.fragment) {
+ if (uri.fragment) |fragment| try writer.print("#{fragment}", .{fragment});
}
-
- if (options.query) if (uri.query) |q| {
- try writer.writeAll("?");
- if (options.raw) {
- try writer.writeAll(q);
- } else {
- try writeEscapedQuery(writer, q);
- }
- };
-
- if (options.fragment) if (uri.fragment) |f| {
- try writer.writeAll("#");
- if (options.raw) {
- try writer.writeAll(f);
- } else {
- try writeEscapedQuery(writer, f);
- }
- };
}
}
pub fn format(
uri: Uri,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
+ comptime fmt_str: []const u8,
+ _: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- _ = options;
-
- const scheme = comptime std.mem.indexOf(u8, fmt, ";") != null or fmt.len == 0;
- const authentication = comptime std.mem.indexOf(u8, fmt, "@") != null or fmt.len == 0;
- const authority = comptime std.mem.indexOf(u8, fmt, "+") != null or fmt.len == 0;
- const path = comptime std.mem.indexOf(u8, fmt, "/") != null or fmt.len == 0;
- const query = comptime std.mem.indexOf(u8, fmt, "?") != null or fmt.len == 0;
- const fragment = comptime std.mem.indexOf(u8, fmt, "#") != null or fmt.len == 0;
- const raw = comptime std.mem.indexOf(u8, fmt, "r") != null or fmt.len == 0;
+ const scheme = comptime std.mem.indexOfScalar(u8, fmt_str, ';') != null or fmt_str.len == 0;
+ const authentication = comptime std.mem.indexOfScalar(u8, fmt_str, '@') != null or fmt_str.len == 0;
+ const authority = comptime std.mem.indexOfScalar(u8, fmt_str, '+') != null or fmt_str.len == 0;
+ const path = comptime std.mem.indexOfScalar(u8, fmt_str, '/') != null or fmt_str.len == 0;
+ const query = comptime std.mem.indexOfScalar(u8, fmt_str, '?') != null or fmt_str.len == 0;
+ const fragment = comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null or fmt_str.len == 0;
return writeToStream(uri, .{
.scheme = scheme,
@@ -334,12 +308,11 @@ pub fn format(
.path = path,
.query = query,
.fragment = fragment,
- .raw = raw,
}, writer);
}
/// Parses the URI or returns an error.
-/// The return value will contain unescaped strings pointing into the
+/// The return value will contain strings pointing into the
/// original `text`. Each component that is provided, will be non-`null`.
pub fn parse(text: []const u8) ParseError!Uri {
var reader: SliceReader = .{ .slice = text };
@@ -353,42 +326,32 @@ pub fn parse(text: []const u8) ParseError!Uri {
return error.InvalidFormat;
}
- var uri = try parseWithoutScheme(reader.readUntilEof());
- uri.scheme = scheme;
-
- return uri;
+ return parseAfterScheme(scheme, reader.readUntilEof());
}
-pub const ResolveInplaceError = ParseError || error{OutOfMemory};
+pub const ResolveInPlaceError = ParseError || error{NoSpaceLeft};
/// Resolves a URI against a base URI, conforming to RFC 3986, Section 5.
-/// Copies `new` to the beginning of `aux_buf`, allowing the slices to overlap,
+/// Copies `new` to the beginning of `aux_buf.*`, allowing the slices to overlap,
/// then parses `new` as a URI, and then resolves the path in place.
/// If a merge needs to take place, the newly constructed path will be stored
-/// in `aux_buf` just after the copied `new`.
-pub fn resolve_inplace(base: Uri, new: []const u8, aux_buf: []u8) ResolveInplaceError!Uri {
- std.mem.copyForwards(u8, aux_buf, new);
+/// in `aux_buf.*` just after the copied `new`, and `aux_buf.*` will be modified
+/// to only contain the remaining unused space.
+pub fn resolve_inplace(base: Uri, new: []const u8, aux_buf: *[]u8) ResolveInPlaceError!Uri {
+ std.mem.copyForwards(u8, aux_buf.*, new);
// At this point, new is an invalid pointer.
- const new_mut = aux_buf[0..new.len];
-
- const new_parsed, const has_scheme = p: {
- break :p .{
- parse(new_mut) catch |first_err| {
- break :p .{
- parseWithoutScheme(new_mut) catch return first_err,
- false,
- };
- },
- true,
- };
- };
+ const new_mut = aux_buf.*[0..new.len];
+ aux_buf.* = aux_buf.*[new.len..];
+ const new_parsed = parse(new_mut) catch |err|
+ (parseAfterScheme("", new_mut) catch return err);
// As you can see above, `new_mut` is not a const pointer.
- const new_path: []u8 = @constCast(new_parsed.path);
+ const new_path: []u8 = @constCast(new_parsed.path.percent_encoded);
- if (has_scheme) return .{
+ if (new_parsed.scheme.len > 0) return .{
.scheme = new_parsed.scheme,
.user = new_parsed.user,
+ .password = new_parsed.password,
.host = new_parsed.host,
.port = new_parsed.port,
.path = remove_dot_segments(new_path),
@@ -399,6 +362,7 @@ pub fn resolve_inplace(base: Uri, new: []const u8, aux_buf: []u8) ResolveInplace
if (new_parsed.host) |host| return .{
.scheme = base.scheme,
.user = new_parsed.user,
+ .password = new_parsed.password,
.host = host,
.port = new_parsed.port,
.path = remove_dot_segments(new_path),
@@ -406,28 +370,21 @@ pub fn resolve_inplace(base: Uri, new: []const u8, aux_buf: []u8) ResolveInplace
.fragment = new_parsed.fragment,
};
- const path, const query = b: {
- if (new_path.len == 0)
- break :b .{
- base.path,
- new_parsed.query orelse base.query,
- };
-
- if (new_path[0] == '/')
- break :b .{
- remove_dot_segments(new_path),
- new_parsed.query,
- };
-
- break :b .{
- try merge_paths(base.path, new_path, aux_buf[new_mut.len..]),
- new_parsed.query,
- };
+ const path, const query = if (new_path.len == 0) .{
+ base.path,
+ new_parsed.query orelse base.query,
+ } else if (new_path[0] == '/') .{
+ remove_dot_segments(new_path),
+ new_parsed.query,
+ } else .{
+ try merge_paths(base.path, new_path, aux_buf),
+ new_parsed.query,
};
return .{
.scheme = base.scheme,
.user = base.user,
+ .password = base.password,
.host = base.host,
.port = base.port,
.path = path,
@@ -437,7 +394,7 @@ pub fn resolve_inplace(base: Uri, new: []const u8, aux_buf: []u8) ResolveInplace
}
/// In-place implementation of RFC 3986, Section 5.2.4.
-fn remove_dot_segments(path: []u8) []u8 {
+fn remove_dot_segments(path: []u8) Component {
var in_i: usize = 0;
var out_i: usize = 0;
while (in_i < path.len) {
@@ -476,28 +433,28 @@ fn remove_dot_segments(path: []u8) []u8 {
}
}
}
- return path[0..out_i];
+ return .{ .percent_encoded = path[0..out_i] };
}
test remove_dot_segments {
{
var buffer = "/a/b/c/./../../g".*;
- try std.testing.expectEqualStrings("/a/g", remove_dot_segments(&buffer));
+ try std.testing.expectEqualStrings("/a/g", remove_dot_segments(&buffer).percent_encoded);
}
}
/// 5.2.3. Merge Paths
-fn merge_paths(base: []const u8, new: []u8, aux: []u8) error{OutOfMemory}![]u8 {
- if (aux.len < base.len + 1 + new.len) return error.OutOfMemory;
- if (base.len == 0) {
- aux[0] = '/';
- @memcpy(aux[1..][0..new.len], new);
- return remove_dot_segments(aux[0 .. new.len + 1]);
+fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component {
+ var aux = std.io.fixedBufferStream(aux_buf.*);
+ if (!base.isEmpty()) {
+ try aux.writer().print("{path}", .{base});
+ aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse
+ return remove_dot_segments(new);
}
- const pos = std.mem.lastIndexOfScalar(u8, base, '/') orelse return remove_dot_segments(new);
- @memcpy(aux[0 .. pos + 1], base[0 .. pos + 1]);
- @memcpy(aux[pos + 1 ..][0..new.len], new);
- return remove_dot_segments(aux[0 .. pos + 1 + new.len]);
+ try aux.writer().print("/{s}", .{new});
+ const merged_path = remove_dot_segments(aux.getWritten());
+ aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..];
+ return merged_path;
}
const SliceReader = struct {
@@ -561,13 +518,6 @@ fn isSchemeChar(c: u8) bool {
};
}
-fn isAuthoritySeparator(c: u8) bool {
- return switch (c) {
- '/', '?', '#' => true,
- else => false,
- };
-}
-
/// reserved = gen-delims / sub-delims
fn isReserved(c: u8) bool {
return isGenLimit(c) or isSubLimit(c);
@@ -598,19 +548,40 @@ fn isUnreserved(c: u8) bool {
};
}
-fn isPathSeparator(c: u8) bool {
- return switch (c) {
- '?', '#' => true,
- else => false,
- };
+fn isUserChar(c: u8) bool {
+ return isUnreserved(c) or isSubLimit(c);
+}
+
+fn isPasswordChar(c: u8) bool {
+ return isUserChar(c) or c == ':';
+}
+
+fn isHostChar(c: u8) bool {
+ return isPasswordChar(c) or c == '[' or c == ']';
}
fn isPathChar(c: u8) bool {
- return isUnreserved(c) or isSubLimit(c) or c == '/' or c == ':' or c == '@';
+ return isUserChar(c) or c == '/' or c == ':' or c == '@';
}
fn isQueryChar(c: u8) bool {
- return isPathChar(c) or c == '?' or c == '%';
+ return isPathChar(c) or c == '?';
+}
+
+const isFragmentChar = isQueryChar;
+
+fn isAuthoritySeparator(c: u8) bool {
+ return switch (c) {
+ '/', '?', '#' => true,
+ else => false,
+ };
+}
+
+fn isPathSeparator(c: u8) bool {
+ return switch (c) {
+ '?', '#' => true,
+ else => false,
+ };
}
fn isQuerySeparator(c: u8) bool {
@@ -623,92 +594,92 @@ fn isQuerySeparator(c: u8) bool {
test "basic" {
const parsed = try parse("https://ziglang.org/download");
try testing.expectEqualStrings("https", parsed.scheme);
- try testing.expectEqualStrings("ziglang.org", parsed.host orelse return error.UnexpectedNull);
- try testing.expectEqualStrings("/download", parsed.path);
+ try testing.expectEqualStrings("ziglang.org", parsed.host.?.percent_encoded);
+ try testing.expectEqualStrings("/download", parsed.path.percent_encoded);
try testing.expectEqual(@as(?u16, null), parsed.port);
}
test "with port" {
const parsed = try parse("http://example:1337/");
try testing.expectEqualStrings("http", parsed.scheme);
- try testing.expectEqualStrings("example", parsed.host orelse return error.UnexpectedNull);
- try testing.expectEqualStrings("/", parsed.path);
+ try testing.expectEqualStrings("example", parsed.host.?.percent_encoded);
+ try testing.expectEqualStrings("/", parsed.path.percent_encoded);
try testing.expectEqual(@as(?u16, 1337), parsed.port);
}
test "should fail gracefully" {
- try std.testing.expectEqual(@as(ParseError!Uri, error.InvalidFormat), parse("foobar://"));
+ try std.testing.expectError(error.InvalidFormat, parse("foobar://"));
}
test "file" {
const parsed = try parse("file:///");
- try std.testing.expectEqualSlices(u8, "file", parsed.scheme);
- try std.testing.expectEqual(@as(?[]const u8, null), parsed.host);
- try std.testing.expectEqualSlices(u8, "/", parsed.path);
+ try std.testing.expectEqualStrings("file", parsed.scheme);
+ try std.testing.expectEqual(@as(?Component, null), parsed.host);
+ try std.testing.expectEqualStrings("/", parsed.path.percent_encoded);
const parsed2 = try parse("file:///an/absolute/path/to/something");
- try std.testing.expectEqualSlices(u8, "file", parsed2.scheme);
- try std.testing.expectEqual(@as(?[]const u8, null), parsed2.host);
- try std.testing.expectEqualSlices(u8, "/an/absolute/path/to/something", parsed2.path);
+ try std.testing.expectEqualStrings("file", parsed2.scheme);
+ try std.testing.expectEqual(@as(?Component, null), parsed2.host);
+ try std.testing.expectEqualStrings("/an/absolute/path/to/something", parsed2.path.percent_encoded);
const parsed3 = try parse("file://localhost/an/absolute/path/to/another/thing/");
- try std.testing.expectEqualSlices(u8, "file", parsed3.scheme);
- try std.testing.expectEqualSlices(u8, "localhost", parsed3.host.?);
- try std.testing.expectEqualSlices(u8, "/an/absolute/path/to/another/thing/", parsed3.path);
+ try std.testing.expectEqualStrings("file", parsed3.scheme);
+ try std.testing.expectEqualStrings("localhost", parsed3.host.?.percent_encoded);
+ try std.testing.expectEqualStrings("/an/absolute/path/to/another/thing/", parsed3.path.percent_encoded);
}
test "scheme" {
- try std.testing.expectEqualSlices(u8, "http", (try parse("http:_")).scheme);
- try std.testing.expectEqualSlices(u8, "scheme-mee", (try parse("scheme-mee:_")).scheme);
- try std.testing.expectEqualSlices(u8, "a.b.c", (try parse("a.b.c:_")).scheme);
- try std.testing.expectEqualSlices(u8, "ab+", (try parse("ab+:_")).scheme);
- try std.testing.expectEqualSlices(u8, "X+++", (try parse("X+++:_")).scheme);
- try std.testing.expectEqualSlices(u8, "Y+-.", (try parse("Y+-.:_")).scheme);
+ try std.testing.expectEqualStrings("http", (try parse("http:_")).scheme);
+ try std.testing.expectEqualStrings("scheme-mee", (try parse("scheme-mee:_")).scheme);
+ try std.testing.expectEqualStrings("a.b.c", (try parse("a.b.c:_")).scheme);
+ try std.testing.expectEqualStrings("ab+", (try parse("ab+:_")).scheme);
+ try std.testing.expectEqualStrings("X+++", (try parse("X+++:_")).scheme);
+ try std.testing.expectEqualStrings("Y+-.", (try parse("Y+-.:_")).scheme);
}
test "authority" {
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://hostname")).host.?);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://hostname")).host.?.percent_encoded);
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://userinfo@hostname")).host.?);
- try std.testing.expectEqualSlices(u8, "userinfo", (try parse("scheme://userinfo@hostname")).user.?);
- try std.testing.expectEqual(@as(?[]const u8, null), (try parse("scheme://userinfo@hostname")).password);
- try std.testing.expectEqual(@as(?[]const u8, null), (try parse("scheme://userinfo@")).host);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://userinfo@hostname")).host.?.percent_encoded);
+ try std.testing.expectEqualStrings("userinfo", (try parse("scheme://userinfo@hostname")).user.?.percent_encoded);
+ try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://userinfo@hostname")).password);
+ try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://userinfo@")).host);
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://user:password@hostname")).host.?);
- try std.testing.expectEqualSlices(u8, "user", (try parse("scheme://user:password@hostname")).user.?);
- try std.testing.expectEqualSlices(u8, "password", (try parse("scheme://user:password@hostname")).password.?);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://user:password@hostname")).host.?.percent_encoded);
+ try std.testing.expectEqualStrings("user", (try parse("scheme://user:password@hostname")).user.?.percent_encoded);
+ try std.testing.expectEqualStrings("password", (try parse("scheme://user:password@hostname")).password.?.percent_encoded);
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://hostname:0")).host.?);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://hostname:0")).host.?.percent_encoded);
try std.testing.expectEqual(@as(u16, 1234), (try parse("scheme://hostname:1234")).port.?);
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://userinfo@hostname:1234")).host.?);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://userinfo@hostname:1234")).host.?.percent_encoded);
try std.testing.expectEqual(@as(u16, 1234), (try parse("scheme://userinfo@hostname:1234")).port.?);
- try std.testing.expectEqualSlices(u8, "userinfo", (try parse("scheme://userinfo@hostname:1234")).user.?);
- try std.testing.expectEqual(@as(?[]const u8, null), (try parse("scheme://userinfo@hostname:1234")).password);
+ try std.testing.expectEqualStrings("userinfo", (try parse("scheme://userinfo@hostname:1234")).user.?.percent_encoded);
+ try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://userinfo@hostname:1234")).password);
- try std.testing.expectEqualSlices(u8, "hostname", (try parse("scheme://user:password@hostname:1234")).host.?);
+ try std.testing.expectEqualStrings("hostname", (try parse("scheme://user:password@hostname:1234")).host.?.percent_encoded);
try std.testing.expectEqual(@as(u16, 1234), (try parse("scheme://user:password@hostname:1234")).port.?);
- try std.testing.expectEqualSlices(u8, "user", (try parse("scheme://user:password@hostname:1234")).user.?);
- try std.testing.expectEqualSlices(u8, "password", (try parse("scheme://user:password@hostname:1234")).password.?);
+ try std.testing.expectEqualStrings("user", (try parse("scheme://user:password@hostname:1234")).user.?.percent_encoded);
+ try std.testing.expectEqualStrings("password", (try parse("scheme://user:password@hostname:1234")).password.?.percent_encoded);
}
test "authority.password" {
- try std.testing.expectEqualSlices(u8, "username", (try parse("scheme://username@a")).user.?);
- try std.testing.expectEqual(@as(?[]const u8, null), (try parse("scheme://username@a")).password);
+ try std.testing.expectEqualStrings("username", (try parse("scheme://username@a")).user.?.percent_encoded);
+ try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://username@a")).password);
- try std.testing.expectEqualSlices(u8, "username", (try parse("scheme://username:@a")).user.?);
- try std.testing.expectEqual(@as(?[]const u8, null), (try parse("scheme://username:@a")).password);
+ try std.testing.expectEqualStrings("username", (try parse("scheme://username:@a")).user.?.percent_encoded);
+ try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://username:@a")).password);
- try std.testing.expectEqualSlices(u8, "username", (try parse("scheme://username:password@a")).user.?);
- try std.testing.expectEqualSlices(u8, "password", (try parse("scheme://username:password@a")).password.?);
+ try std.testing.expectEqualStrings("username", (try parse("scheme://username:password@a")).user.?.percent_encoded);
+ try std.testing.expectEqualStrings("password", (try parse("scheme://username:password@a")).password.?.percent_encoded);
- try std.testing.expectEqualSlices(u8, "username", (try parse("scheme://username::@a")).user.?);
- try std.testing.expectEqualSlices(u8, ":", (try parse("scheme://username::@a")).password.?);
+ try std.testing.expectEqualStrings("username", (try parse("scheme://username::@a")).user.?.percent_encoded);
+ try std.testing.expectEqualStrings(":", (try parse("scheme://username::@a")).password.?.percent_encoded);
}
fn testAuthorityHost(comptime hostlist: anytype) !void {
inline for (hostlist) |hostname| {
- try std.testing.expectEqualSlices(u8, hostname, (try parse("scheme://" ++ hostname)).host.?);
+ try std.testing.expectEqualStrings(hostname, (try parse("scheme://" ++ hostname)).host.?.percent_encoded);
}
}
@@ -761,11 +732,11 @@ test "RFC example 1" {
.scheme = uri[0..3],
.user = null,
.password = null,
- .host = uri[6..17],
+ .host = .{ .percent_encoded = uri[6..17] },
.port = 8042,
- .path = uri[22..33],
- .query = uri[34..45],
- .fragment = uri[46..50],
+ .path = .{ .percent_encoded = uri[22..33] },
+ .query = .{ .percent_encoded = uri[34..45] },
+ .fragment = .{ .percent_encoded = uri[46..50] },
}, try parse(uri));
}
@@ -777,7 +748,7 @@ test "RFC example 2" {
.password = null,
.host = null,
.port = null,
- .path = uri[4..],
+ .path = .{ .percent_encoded = uri[4..] },
.query = null,
.fragment = null,
}, try parse(uri));
@@ -838,55 +809,60 @@ test "Special test" {
_ = try parse("https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be&t=0");
}
-test "URI escaping" {
- const input = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
- const expected = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad";
+test "URI percent encoding" {
+ try std.testing.expectFmt(
+ "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad",
+ "{%}",
+ .{Component{ .raw = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad" }},
+ );
+}
- const actual = try escapeString(std.testing.allocator, input);
- defer std.testing.allocator.free(actual);
+test "URI percent decoding" {
+ {
+ const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
+ var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
- try std.testing.expectEqualSlices(u8, expected, actual);
-}
+ try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
+
+ var output: [expected.len]u8 = undefined;
+ try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
+
+ try std.testing.expectEqualStrings(expected, percentDecodeInPlace(&input));
+ }
-test "URI unescaping" {
- const input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad";
- const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
+ {
+ const expected = "/abc%";
+ var input = expected.*;
- const actual = try unescapeString(std.testing.allocator, input);
- defer std.testing.allocator.free(actual);
+ try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
- try std.testing.expectEqualSlices(u8, expected, actual);
+ var output: [expected.len]u8 = undefined;
+ try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
- const decoded = try unescapeString(std.testing.allocator, "/abc%");
- defer std.testing.allocator.free(decoded);
- try std.testing.expectEqualStrings("/abc%", decoded);
+ try std.testing.expectEqualStrings(expected, percentDecodeInPlace(&input));
+ }
}
-test "URI query escaping" {
+test "URI query encoding" {
const address = "https://objects.githubusercontent.com/?response-content-type=application%2Foctet-stream";
const parsed = try Uri.parse(address);
- // format the URI to escape it
- const formatted_uri = try std.fmt.allocPrint(std.testing.allocator, "{/?}", .{parsed});
- defer std.testing.allocator.free(formatted_uri);
- try std.testing.expectEqualStrings("/?response-content-type=application%2Foctet-stream", formatted_uri);
+ // format the URI to percent encode it
+ try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{/?}", .{parsed});
}
test "format" {
- const uri = Uri{
+ const uri: Uri = .{
.scheme = "file",
.user = null,
.password = null,
.host = null,
.port = null,
- .path = "/foo/bar/baz",
+ .path = .{ .raw = "/foo/bar/baz" },
.query = null,
.fragment = null,
};
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- try buf.writer().print("{;/?#}", .{uri});
- try std.testing.expectEqualSlices(u8, "file:/foo/bar/baz", buf.items);
+ try std.testing.expectFmt("file:/foo/bar/baz", "{;/?#}", .{uri});
}
test "URI malformed input" {
@@ -894,3 +870,7 @@ test "URI malformed input" {
try std.testing.expectError(error.InvalidFormat, std.Uri.parse("http://]@["));
try std.testing.expectError(error.InvalidFormat, std.Uri.parse("http://lo]s\x85hc@[/8\x10?0Q"));
}
+
+const std = @import("std.zig");
+const testing = std.testing;
+const Uri = @This();
diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig
index d75dd3bf00..cd2e4bc296 100644
--- a/lib/std/c/haiku.zig
+++ b/lib/std/c/haiku.zig
@@ -5,28 +5,18 @@ const maxInt = std.math.maxInt;
const iovec = std.posix.iovec;
const iovec_const = std.posix.iovec_const;
-extern "c" fn _errnop() *c_int;
+pub extern "root" fn find_directory(which: directory_which, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64;
-pub const _errno = _errnop;
-
-pub extern "c" fn find_directory(which: directory_which, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64;
-
-pub extern "c" fn find_thread(thread_name: ?*anyopaque) i32;
+pub extern "root" fn find_thread(thread_name: ?*anyopaque) i32;
-pub extern "c" fn get_system_info(system_info: *system_info) usize;
+pub extern "root" fn get_system_info(system_info: *system_info) usize;
-pub extern "c" fn _get_team_info(team: c_int, team_info: *team_info, size: usize) i32;
+pub extern "root" fn _get_team_info(team: i32, team_info: *team_info, size: usize) i32;
-pub extern "c" fn _get_next_area_info(team: c_int, cookie: *i64, area_info: *area_info, size: usize) i32;
+pub extern "root" fn _get_next_area_info(team: i32, cookie: *i64, area_info: *area_info, size: usize) i32;
// TODO revisit if abi changes or better option becomes apparent
-pub extern "c" fn _get_next_image_info(team: c_int, cookie: *i32, image_info: *image_info, size: usize) i32;
-
-pub extern "c" fn _kern_read_dir(fd: c_int, buf_ptr: [*]u8, nbytes: usize, maxcount: u32) usize;
-
-pub extern "c" fn _kern_read_stat(fd: c_int, path_ptr: [*]u8, traverse_link: bool, st: *Stat, stat_size: i32) usize;
-
-pub extern "c" fn _kern_get_current_team() i32;
+pub extern "root" fn _get_next_image_info(team: i32, cookie: *i32, image_info: *image_info, size: usize) i32;
pub const sem_t = extern struct {
type: i32,
@@ -45,7 +35,7 @@ pub const pthread_attr_t = extern struct {
__stack_address: ?*anyopaque,
};
-pub const EAI = enum(c_int) {
+pub const EAI = enum(i32) {
/// address family for hostname not supported
ADDRFAMILY = 1,
@@ -99,11 +89,7 @@ pub const AI = struct {
pub const AI_NUMERICSERV = AI.NUMERICSERV;
-pub const fd_t = c_int;
-pub const pid_t = c_int;
-pub const uid_t = u32;
-pub const gid_t = u32;
-pub const mode_t = c_uint;
+pub const fd_t = i32;
pub const socklen_t = u32;
@@ -129,8 +115,8 @@ pub const dl_phdr_info = extern struct {
};
pub const Flock = extern struct {
- type: c_short,
- whence: c_short,
+ type: i16,
+ whence: i16,
start: off_t,
len: off_t,
pid: pid_t,
@@ -159,54 +145,6 @@ pub const msghdr = extern struct {
msg_flags: i32,
};
-pub const off_t = i64;
-pub const ino_t = u64;
-
-pub const Stat = extern struct {
- dev: i32,
- ino: u64,
- mode: u32,
- nlink: i32,
- uid: i32,
- gid: i32,
- size: i64,
- rdev: i32,
- blksize: i32,
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
- crtim: timespec,
- st_type: u32,
- blocks: i64,
-
- pub fn atime(self: @This()) timespec {
- return self.atim;
- }
- pub fn mtime(self: @This()) timespec {
- return self.mtim;
- }
- pub fn ctime(self: @This()) timespec {
- return self.ctim;
- }
- pub fn birthtime(self: @This()) timespec {
- return self.crtim;
- }
-};
-
-pub const timespec = extern struct {
- tv_sec: isize,
- tv_nsec: isize,
-};
-
-pub const dirent = extern struct {
- dev: i32,
- pdev: i32,
- ino: i64,
- pino: i64,
- reclen: u16,
- name: [256]u8,
-};
-
pub const B_OS_NAME_LENGTH = 32; // OS.h
pub const area_info = extern struct {
@@ -354,17 +292,6 @@ pub const PROT = struct {
pub const NONE = 0x00;
};
-pub const CLOCK = struct {
- /// system-wide monotonic clock (aka system time)
- pub const MONOTONIC = 0;
- /// system-wide real time clock
- pub const REALTIME = -1;
- /// clock measuring the used CPU time of the current process
- pub const PROCESS_CPUTIME_ID = -2;
- /// clock measuring the used CPU time of the current thread
- pub const THREAD_CPUTIME_ID = -3;
-};
-
pub const MSF = struct {
pub const ASYNC = 1;
pub const INVALIDATE = 2;
@@ -404,159 +331,526 @@ pub const W = struct {
}
};
-// /system/develop/headers/posix/poll.h
+// 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 nfds_t = usize;
+pub const F = struct {
+ pub const DUPFD = 0x0001;
+ pub const GETFD = 0x0002;
+ pub const SETFD = 0x0004;
+ pub const GETFL = 0x0008;
+ pub const SETFL = 0x0010;
-pub const pollfd = extern struct {
- fd: i32,
- events: i16,
- revents: i16,
-};
+ pub const GETLK = 0x0020;
+ pub const SETLK = 0x0080;
+ pub const SETLKW = 0x0100;
+ pub const DUPFD_CLOEXEC = 0x0200;
-pub const POLL = struct {
- /// any readable data available
- pub const IN = 0x0001;
- /// file descriptor is writeable
- pub const OUT = 0x0002;
- pub const RDNORM = IN;
- pub const WRNORM = OUT;
- /// priority readable data
- pub const RDBAND = 0x0008;
- /// priority data can be written
- pub const WRBAND = 0x0010;
- /// high priority readable data
- pub const PRI = 0x0020;
+ pub const RDLCK = 0x0040;
+ pub const UNLCK = 0x0200;
+ pub const WRLCK = 0x0400;
+};
- /// errors pending
- pub const ERR = 0x0004;
- /// disconnected
- pub const HUP = 0x0080;
- /// invalid file descriptor
- pub const NVAL = 0x1000;
+pub const LOCK = struct {
+ pub const SH = 0x01;
+ pub const EX = 0x02;
+ pub const NB = 0x04;
+ pub const UN = 0x08;
};
-// /system/develop/headers/posix/signal.h
+pub const FD_CLOEXEC = 1;
-pub const sigset_t = u64;
-pub const empty_sigset: sigset_t = 0;
-pub const filled_sigset = ~@as(sigset_t, 0);
+pub const SEEK = struct {
+ pub const SET = 0;
+ pub const CUR = 1;
+ pub const END = 2;
+};
-pub const SIG = struct {
- pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
- pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
- pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+pub const SOCK = struct {
+ pub const STREAM = 1;
+ pub const DGRAM = 2;
+ pub const RAW = 3;
+ pub const SEQPACKET = 5;
- pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
+ /// WARNING: this flag is not supported by windows socket functions directly,
+ /// it is only supported by std.os.socket. Be sure that this value does
+ /// not share any bits with any of the `SOCK` values.
+ pub const CLOEXEC = 0x10000;
+ /// WARNING: this flag is not supported by windows socket functions directly,
+ /// it is only supported by std.os.socket. Be sure that this value does
+ /// not share any bits with any of the `SOCK` values.
+ pub const NONBLOCK = 0x20000;
+};
- pub const HUP = 1;
- pub const INT = 2;
- pub const QUIT = 3;
- pub const ILL = 4;
- pub const CHLD = 5;
- pub const ABRT = 6;
- pub const IOT = ABRT;
- pub const PIPE = 7;
- pub const FPE = 8;
- pub const KILL = 9;
- pub const STOP = 10;
- pub const SEGV = 11;
- pub const CONT = 12;
- pub const TSTP = 13;
- pub const ALRM = 14;
- pub const TERM = 15;
- pub const TTIN = 16;
- pub const TTOU = 17;
- pub const USR1 = 18;
- pub const USR2 = 19;
- pub const WINCH = 20;
- pub const KILLTHR = 21;
- pub const TRAP = 22;
- pub const POLL = 23;
- pub const PROF = 24;
- pub const SYS = 25;
- pub const URG = 26;
- pub const VTALRM = 27;
- pub const XCPU = 28;
- pub const XFSZ = 29;
- pub const BUS = 30;
- pub const RESERVED1 = 31;
- pub const RESERVED2 = 32;
+pub const SO = struct {
+ pub const ACCEPTCONN = 0x00000001;
+ pub const BROADCAST = 0x00000002;
+ pub const DEBUG = 0x00000004;
+ pub const DONTROUTE = 0x00000008;
+ pub const KEEPALIVE = 0x00000010;
+ pub const OOBINLINE = 0x00000020;
+ pub const REUSEADDR = 0x00000040;
+ pub const REUSEPORT = 0x00000080;
+ pub const USELOOPBACK = 0x00000100;
+ pub const LINGER = 0x00000200;
- pub const BLOCK = 1;
- pub const UNBLOCK = 2;
- pub const SETMASK = 3;
+ pub const SNDBUF = 0x40000001;
+ pub const SNDLOWAT = 0x40000002;
+ pub const SNDTIMEO = 0x40000003;
+ pub const RCVBUF = 0x40000004;
+ pub const RCVLOWAT = 0x40000005;
+ pub const RCVTIMEO = 0x40000006;
+ pub const ERROR = 0x40000007;
+ pub const TYPE = 0x40000008;
+ pub const NONBLOCK = 0x40000009;
+ pub const BINDTODEVICE = 0x4000000a;
+ pub const PEERCRED = 0x4000000b;
};
-pub const siginfo_t = extern struct {
- signo: c_int,
- code: c_int,
- errno: c_int,
+pub const SOL = struct {
+ pub const SOCKET = -1;
+};
- pid: pid_t,
- uid: uid_t,
- addr: *allowzero anyopaque,
+pub const PF = struct {
+ pub const UNSPEC = AF.UNSPEC;
+ pub const INET = AF.INET;
+ pub const ROUTE = AF.ROUTE;
+ pub const LINK = AF.LINK;
+ pub const INET6 = AF.INET6;
+ pub const LOCAL = AF.LOCAL;
+ pub const UNIX = AF.UNIX;
+ pub const BLUETOOTH = AF.BLUETOOTH;
};
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
- pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+pub const AF = struct {
+ pub const UNSPEC = 0;
+ pub const INET = 1;
+ pub const APPLETALK = 2;
+ pub const ROUTE = 3;
+ pub const LINK = 4;
+ pub const INET6 = 5;
+ pub const DLI = 6;
+ pub const IPX = 7;
+ pub const NOTIFY = 8;
+ pub const LOCAL = 9;
+ pub const UNIX = LOCAL;
+ pub const BLUETOOTH = 10;
+ pub const MAX = 11;
+};
- /// signal handler
- handler: extern union {
- handler: handler_fn,
- sigaction: sigaction_fn,
- },
+pub const DT = struct {};
- /// signal mask to apply
- mask: sigset_t,
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
- /// see signal options
- flags: c_int,
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
- /// will be passed to the signal handler, BeOS extension
- userdata: *allowzero anyopaque = undefined,
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+pub const EVFILT_READ = -1;
+pub const EVFILT_WRITE = -2;
+
+/// attached to aio requests
+pub const EVFILT_AIO = -3;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = -4;
+
+/// attached to struct proc
+pub const EVFILT_PROC = -5;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = -6;
+
+/// timers
+pub const EVFILT_TIMER = -7;
+
+/// Process descriptors
+pub const EVFILT_PROCDESC = -8;
+
+/// Filesystem events
+pub const EVFILT_FS = -9;
+
+pub const EVFILT_LIO = -10;
+
+/// User events
+pub const EVFILT_USER = -11;
+
+/// Sendfile events
+pub const EVFILT_SENDFILE = -12;
+
+pub const EVFILT_EMPTY = -13;
+
+pub const T = struct {
+ pub const CGETA = 0x8000;
+ pub const CSETA = 0x8001;
+ pub const CSETAF = 0x8002;
+ pub const CSETAW = 0x8003;
+ pub const CWAITEVENT = 0x8004;
+ pub const CSBRK = 0x8005;
+ pub const CFLSH = 0x8006;
+ pub const CXONC = 0x8007;
+ pub const CQUERYCONNECTED = 0x8008;
+ pub const CGETBITS = 0x8009;
+ pub const CSETDTR = 0x8010;
+ pub const CSETRTS = 0x8011;
+ pub const IOCGWINSZ = 0x8012;
+ pub const IOCSWINSZ = 0x8013;
+ pub const CVTIME = 0x8014;
+ pub const IOCGPGRP = 0x8015;
+ pub const IOCSPGRP = 0x8016;
+ pub const IOCSCTTY = 0x8017;
+ pub const IOCMGET = 0x8018;
+ pub const IOCMSET = 0x8019;
+ pub const IOCSBRK = 0x8020;
+ pub const IOCCBRK = 0x8021;
+ pub const IOCMBIS = 0x8022;
+ pub const IOCMBIC = 0x8023;
+ pub const IOCGSID = 0x8024;
+
+ pub const FIONREAD = 0xbe000001;
+ pub const FIONBIO = 0xbe000000;
};
-pub const SA = struct {
- pub const NOCLDSTOP = 0x01;
- pub const NOCLDWAIT = 0x02;
- pub const RESETHAND = 0x04;
- pub const NODEFER = 0x08;
- pub const RESTART = 0x10;
- pub const ONSTACK = 0x20;
- pub const SIGINFO = 0x40;
- pub const NOMASK = NODEFER;
- pub const STACK = ONSTACK;
- pub const ONESHOT = RESETHAND;
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
};
-pub const SS = struct {
- pub const ONSTACK = 0x1;
- pub const DISABLE = 0x2;
+pub const S = struct {
+ pub const IFMT = 0o170000;
+ pub const IFSOCK = 0o140000;
+ pub const IFLNK = 0o120000;
+ pub const IFREG = 0o100000;
+ pub const IFBLK = 0o060000;
+ pub const IFDIR = 0o040000;
+ pub const IFCHR = 0o020000;
+ pub const IFIFO = 0o010000;
+ pub const INDEX_DIR = 0o4000000000;
+
+ pub const IUMSK = 0o7777;
+ pub const ISUID = 0o4000;
+ pub const ISGID = 0o2000;
+ pub const ISVTX = 0o1000;
+ pub const IRWXU = 0o700;
+ pub const IRUSR = 0o400;
+ pub const IWUSR = 0o200;
+ pub const IXUSR = 0o100;
+ pub const IRWXG = 0o070;
+ pub const IRGRP = 0o040;
+ pub const IWGRP = 0o020;
+ pub const IXGRP = 0o010;
+ pub const IRWXO = 0o007;
+ pub const IROTH = 0o004;
+ pub const IWOTH = 0o002;
+ pub const IXOTH = 0o001;
+
+ pub fn ISREG(m: u32) bool {
+ return m & IFMT == IFREG;
+ }
+
+ pub fn ISLNK(m: u32) bool {
+ return m & IFMT == IFLNK;
+ }
+
+ pub fn ISBLK(m: u32) bool {
+ return m & IFMT == IFBLK;
+ }
+
+ pub fn ISDIR(m: u32) bool {
+ return m & IFMT == IFDIR;
+ }
+
+ pub fn ISCHR(m: u32) bool {
+ return m & IFMT == IFCHR;
+ }
+
+ pub fn ISFIFO(m: u32) bool {
+ return m & IFMT == IFIFO;
+ }
+
+ pub fn ISSOCK(m: u32) bool {
+ return m & IFMT == IFSOCK;
+ }
+
+ pub fn ISINDEX(m: u32) bool {
+ return m & INDEX_DIR == INDEX_DIR;
+ }
};
-pub const MINSIGSTKSZ = 8192;
-pub const SIGSTKSZ = 16384;
+pub const HOST_NAME_MAX = 255;
-pub const stack_t = extern struct {
- sp: [*]u8,
- size: isize,
+pub const addrinfo = extern struct {
flags: i32,
+ family: i32,
+ socktype: i32,
+ protocol: i32,
+ addrlen: socklen_t,
+ canonname: ?[*:0]u8,
+ addr: ?*sockaddr,
+ next: ?*addrinfo,
};
-pub const NSIG = 65;
+pub const IPPROTO = struct {
+ pub const IP = 0;
+ pub const HOPOPTS = 0;
+ pub const ICMP = 1;
+ pub const IGMP = 2;
+ pub const TCP = 6;
+ pub const UDP = 17;
+ pub const IPV6 = 41;
+ pub const ROUTING = 43;
+ pub const FRAGMENT = 44;
+ pub const ESP = 50;
+ pub const AH = 51;
+ pub const ICMPV6 = 58;
+ pub const NONE = 59;
+ pub const DSTOPTS = 60;
+ pub const ETHERIP = 97;
+ pub const RAW = 255;
+ pub const MAX = 256;
+};
-pub const mcontext_t = vregs;
+pub const rlimit_resource = enum(i32) {
+ CORE = 0,
+ CPU = 1,
+ DATA = 2,
+ FSIZE = 3,
+ NOFILE = 4,
+ STACK = 5,
+ AS = 6,
+ NOVMON = 7,
+ _,
+};
-pub const ucontext_t = extern struct {
- link: ?*ucontext_t,
- sigmask: sigset_t,
- stack: stack_t,
- mcontext: mcontext_t,
+pub const rlim_t = i64;
+
+pub const RLIM = struct {
+ /// No limit
+ pub const INFINITY: rlim_t = (1 << 63) - 1;
+
+ pub const SAVED_MAX = INFINITY;
+ pub const SAVED_CUR = INFINITY;
+};
+
+pub const rlimit = extern struct {
+ /// Soft limit
+ cur: rlim_t,
+ /// Hard limit
+ max: rlim_t,
+};
+
+pub const SHUT = struct {
+ pub const RD = 0;
+ pub const WR = 1;
+ pub const RDWR = 2;
+};
+
+// TODO fill out if needed
+pub const directory_which = enum(i32) {
+ B_USER_SETTINGS_DIRECTORY = 0xbbe,
+
+ _,
+};
+
+pub const MSG_NOSIGNAL = 0x0800;
+
+// /system/develop/headers/os/kernel/OS.h
+
+pub const area_id = i32;
+pub const port_id = i32;
+pub const sem_id = i32;
+pub const team_id = i32;
+pub const thread_id = i32;
+
+// /system/develop/headers/os/support/Errors.h
+
+pub const E = enum(i32) {
+ pub const B_GENERAL_ERROR_BASE: i32 = std.math.minInt(i32);
+ pub const B_OS_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x1000;
+ pub const B_APP_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x2000;
+ pub const B_INTERFACE_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x3000;
+ pub const B_MEDIA_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x4000;
+ pub const B_TRANSLATION_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x4800;
+ pub const B_MIDI_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x5000;
+ pub const B_STORAGE_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x6000;
+ pub const B_POSIX_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x7000;
+ pub const B_MAIL_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x8000;
+ pub const B_PRINT_ERROR_BASE = B_GENERAL_ERROR_BASE + 0x9000;
+ pub const B_DEVICE_ERROR_BASE = B_GENERAL_ERROR_BASE + 0xa000;
+
+ pub const B_ERRORS_END = B_GENERAL_ERROR_BASE + 0xffff;
+
+ pub const B_NO_MEMORY = B_GENERAL_ERROR_BASE + 0;
+ pub const B_IO_ERROR = B_GENERAL_ERROR_BASE + 1;
+ pub const B_PERMISSION_DENIED = B_GENERAL_ERROR_BASE + 2;
+ pub const B_BAD_INDEX = B_GENERAL_ERROR_BASE + 3;
+ pub const B_BAD_TYPE = B_GENERAL_ERROR_BASE + 4;
+ pub const B_BAD_VALUE = B_GENERAL_ERROR_BASE + 5;
+ pub const B_MISMATCHED_VALUES = B_GENERAL_ERROR_BASE + 6;
+ pub const B_NAME_NOT_FOUND = B_GENERAL_ERROR_BASE + 7;
+ pub const B_NAME_IN_USE = B_GENERAL_ERROR_BASE + 8;
+ pub const B_TIMED_OUT = B_GENERAL_ERROR_BASE + 9;
+ pub const B_INTERRUPTED = B_GENERAL_ERROR_BASE + 10;
+ pub const B_WOULD_BLOCK = B_GENERAL_ERROR_BASE + 11;
+ pub const B_CANCELED = B_GENERAL_ERROR_BASE + 12;
+ pub const B_NO_INIT = B_GENERAL_ERROR_BASE + 13;
+ pub const B_NOT_INITIALIZED = B_GENERAL_ERROR_BASE + 13;
+ pub const B_BUSY = B_GENERAL_ERROR_BASE + 14;
+ pub const B_NOT_ALLOWED = B_GENERAL_ERROR_BASE + 15;
+ pub const B_BAD_DATA = B_GENERAL_ERROR_BASE + 16;
+ pub const B_DONT_DO_THAT = B_GENERAL_ERROR_BASE + 17;
+
+ pub const B_BAD_IMAGE_ID = B_OS_ERROR_BASE + 0x300;
+ pub const B_BAD_ADDRESS = B_OS_ERROR_BASE + 0x301;
+ pub const B_NOT_AN_EXECUTABLE = B_OS_ERROR_BASE + 0x302;
+ pub const B_MISSING_LIBRARY = B_OS_ERROR_BASE + 0x303;
+ pub const B_MISSING_SYMBOL = B_OS_ERROR_BASE + 0x304;
+ pub const B_UNKNOWN_EXECUTABLE = B_OS_ERROR_BASE + 0x305;
+ pub const B_LEGACY_EXECUTABLE = B_OS_ERROR_BASE + 0x306;
+
+ pub const B_FILE_ERROR = B_STORAGE_ERROR_BASE + 0;
+ pub const B_FILE_EXISTS = B_STORAGE_ERROR_BASE + 2;
+ pub const B_ENTRY_NOT_FOUND = B_STORAGE_ERROR_BASE + 3;
+ pub const B_NAME_TOO_LONG = B_STORAGE_ERROR_BASE + 4;
+ pub const B_NOT_A_DIRECTORY = B_STORAGE_ERROR_BASE + 5;
+ pub const B_DIRECTORY_NOT_EMPTY = B_STORAGE_ERROR_BASE + 6;
+ pub const B_DEVICE_FULL = B_STORAGE_ERROR_BASE + 7;
+ pub const B_READ_ONLY_DEVICE = B_STORAGE_ERROR_BASE + 8;
+ pub const B_IS_A_DIRECTORY = B_STORAGE_ERROR_BASE + 9;
+ pub const B_NO_MORE_FDS = B_STORAGE_ERROR_BASE + 10;
+ pub const B_CROSS_DEVICE_LINK = B_STORAGE_ERROR_BASE + 11;
+ pub const B_LINK_LIMIT = B_STORAGE_ERROR_BASE + 12;
+ pub const B_BUSTED_PIPE = B_STORAGE_ERROR_BASE + 13;
+ pub const B_UNSUPPORTED = B_STORAGE_ERROR_BASE + 14;
+ pub const B_PARTITION_TOO_SMALL = B_STORAGE_ERROR_BASE + 15;
+ pub const B_PARTIAL_READ = B_STORAGE_ERROR_BASE + 16;
+ pub const B_PARTIAL_WRITE = B_STORAGE_ERROR_BASE + 17;
+
+ SUCCESS = 0,
+
+ @"2BIG" = B_POSIX_ERROR_BASE + 1,
+ CHILD = B_POSIX_ERROR_BASE + 2,
+ DEADLK = B_POSIX_ERROR_BASE + 3,
+ FBIG = B_POSIX_ERROR_BASE + 4,
+ MLINK = B_POSIX_ERROR_BASE + 5,
+ NFILE = B_POSIX_ERROR_BASE + 6,
+ NODEV = B_POSIX_ERROR_BASE + 7,
+ NOLCK = B_POSIX_ERROR_BASE + 8,
+ NOSYS = B_POSIX_ERROR_BASE + 9,
+ NOTTY = B_POSIX_ERROR_BASE + 10,
+ NXIO = B_POSIX_ERROR_BASE + 11,
+ SPIPE = B_POSIX_ERROR_BASE + 12,
+ SRCH = B_POSIX_ERROR_BASE + 13,
+ FPOS = B_POSIX_ERROR_BASE + 14,
+ SIGPARM = B_POSIX_ERROR_BASE + 15,
+ DOM = B_POSIX_ERROR_BASE + 16,
+ RANGE = B_POSIX_ERROR_BASE + 17,
+ PROTOTYPE = B_POSIX_ERROR_BASE + 18,
+ PROTONOSUPPORT = B_POSIX_ERROR_BASE + 19,
+ PFNOSUPPORT = B_POSIX_ERROR_BASE + 20,
+ AFNOSUPPORT = B_POSIX_ERROR_BASE + 21,
+ ADDRINUSE = B_POSIX_ERROR_BASE + 22,
+ ADDRNOTAVAIL = B_POSIX_ERROR_BASE + 23,
+ NETDOWN = B_POSIX_ERROR_BASE + 24,
+ NETUNREACH = B_POSIX_ERROR_BASE + 25,
+ NETRESET = B_POSIX_ERROR_BASE + 26,
+ CONNABORTED = B_POSIX_ERROR_BASE + 27,
+ CONNRESET = B_POSIX_ERROR_BASE + 28,
+ ISCONN = B_POSIX_ERROR_BASE + 29,
+ NOTCONN = B_POSIX_ERROR_BASE + 30,
+ SHUTDOWN = B_POSIX_ERROR_BASE + 31,
+ CONNREFUSED = B_POSIX_ERROR_BASE + 32,
+ HOSTUNREACH = B_POSIX_ERROR_BASE + 33,
+ NOPROTOOPT = B_POSIX_ERROR_BASE + 34,
+ NOBUFS = B_POSIX_ERROR_BASE + 35,
+ INPROGRESS = B_POSIX_ERROR_BASE + 36,
+ ALREADY = B_POSIX_ERROR_BASE + 37,
+ ILSEQ = B_POSIX_ERROR_BASE + 38,
+ NOMSG = B_POSIX_ERROR_BASE + 39,
+ STALE = B_POSIX_ERROR_BASE + 40,
+ OVERFLOW = B_POSIX_ERROR_BASE + 41,
+ MSGSIZE = B_POSIX_ERROR_BASE + 42,
+ OPNOTSUPP = B_POSIX_ERROR_BASE + 43,
+ NOTSOCK = B_POSIX_ERROR_BASE + 44,
+ HOSTDOWN = B_POSIX_ERROR_BASE + 45,
+ BADMSG = B_POSIX_ERROR_BASE + 46,
+ CANCELED = B_POSIX_ERROR_BASE + 47,
+ DESTADDRREQ = B_POSIX_ERROR_BASE + 48,
+ DQUOT = B_POSIX_ERROR_BASE + 49,
+ IDRM = B_POSIX_ERROR_BASE + 50,
+ MULTIHOP = B_POSIX_ERROR_BASE + 51,
+ NODATA = B_POSIX_ERROR_BASE + 52,
+ NOLINK = B_POSIX_ERROR_BASE + 53,
+ NOSR = B_POSIX_ERROR_BASE + 54,
+ NOSTR = B_POSIX_ERROR_BASE + 55,
+ NOTSUP = B_POSIX_ERROR_BASE + 56,
+ PROTO = B_POSIX_ERROR_BASE + 57,
+ TIME = B_POSIX_ERROR_BASE + 58,
+ TXTBSY = B_POSIX_ERROR_BASE + 59,
+ NOATTR = B_POSIX_ERROR_BASE + 60,
+ NOTRECOVERABLE = B_POSIX_ERROR_BASE + 61,
+ OWNERDEAD = B_POSIX_ERROR_BASE + 62,
+
+ NOMEM = B_NO_MEMORY,
+
+ ACCES = B_PERMISSION_DENIED,
+ INTR = B_INTERRUPTED,
+ IO = B_IO_ERROR,
+ BUSY = B_BUSY,
+ FAULT = B_BAD_ADDRESS,
+ TIMEDOUT = B_TIMED_OUT,
+ /// Also used for WOULDBLOCK
+ AGAIN = B_WOULD_BLOCK,
+ BADF = B_FILE_ERROR,
+ EXIST = B_FILE_EXISTS,
+ INVAL = B_BAD_VALUE,
+ NAMETOOLONG = B_NAME_TOO_LONG,
+ NOENT = B_ENTRY_NOT_FOUND,
+ PERM = B_NOT_ALLOWED,
+ NOTDIR = B_NOT_A_DIRECTORY,
+ ISDIR = B_IS_A_DIRECTORY,
+ NOTEMPTY = B_DIRECTORY_NOT_EMPTY,
+ NOSPC = B_DEVICE_FULL,
+ ROFS = B_READ_ONLY_DEVICE,
+ MFILE = B_NO_MORE_FDS,
+ XDEV = B_CROSS_DEVICE_LINK,
+ LOOP = B_LINK_LIMIT,
+ NOEXEC = B_NOT_AN_EXECUTABLE,
+ PIPE = B_BUSTED_PIPE,
+
+ _,
};
+// /system/develop/headers/os/support/SupportDefs.h
+
+pub const status_t = i32;
+
// /system/develop/headers/posix/arch/*/signal.h
pub const vregs = switch (builtin.cpu.arch) {
@@ -822,445 +1116,278 @@ pub const vregs = switch (builtin.cpu.arch) {
else => void,
};
-// 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 F = struct {
- pub const DUPFD = 0x0001;
- pub const GETFD = 0x0002;
- pub const SETFD = 0x0004;
- pub const GETFL = 0x0008;
- pub const SETFL = 0x0010;
-
- pub const GETLK = 0x0020;
- pub const SETLK = 0x0080;
- pub const SETLKW = 0x0100;
- pub const DUPFD_CLOEXEC = 0x0200;
-
- pub const RDLCK = 0x0040;
- pub const UNLCK = 0x0200;
- pub const WRLCK = 0x0400;
-};
-
-pub const LOCK = struct {
- pub const SH = 0x01;
- pub const EX = 0x02;
- pub const NB = 0x04;
- pub const UN = 0x08;
-};
-
-pub const FD_CLOEXEC = 1;
-
-pub const SEEK = struct {
- pub const SET = 0;
- pub const CUR = 1;
- pub const END = 2;
+// /system/develop/headers/posix/dirent.h
+
+pub const DirEnt = extern struct {
+ /// device
+ dev: dev_t,
+ /// parent device (only for queries)
+ pdev: dev_t,
+ /// inode number
+ ino: ino_t,
+ /// parent inode (only for queries)
+ pino: ino_t,
+ /// length of this record, not the name
+ reclen: u16,
+ /// name of the entry (null byte terminated)
+ name: [0]u8,
+ pub fn getName(dirent: *const DirEnt) [*:0]const u8 {
+ return @ptrCast(&dirent.name);
+ }
};
-pub const SOCK = struct {
- pub const STREAM = 1;
- pub const DGRAM = 2;
- pub const RAW = 3;
- pub const SEQPACKET = 5;
+// /system/develop/headers/posix/errno.h
- /// WARNING: this flag is not supported by windows socket functions directly,
- /// it is only supported by std.os.socket. Be sure that this value does
- /// not share any bits with any of the `SOCK` values.
- pub const CLOEXEC = 0x10000;
- /// WARNING: this flag is not supported by windows socket functions directly,
- /// it is only supported by std.os.socket. Be sure that this value does
- /// not share any bits with any of the `SOCK` values.
- pub const NONBLOCK = 0x20000;
-};
+extern "root" fn _errnop() *i32;
+pub const _errno = _errnop;
-pub const SO = struct {
- pub const ACCEPTCONN = 0x00000001;
- pub const BROADCAST = 0x00000002;
- pub const DEBUG = 0x00000004;
- pub const DONTROUTE = 0x00000008;
- pub const KEEPALIVE = 0x00000010;
- pub const OOBINLINE = 0x00000020;
- pub const REUSEADDR = 0x00000040;
- pub const REUSEPORT = 0x00000080;
- pub const USELOOPBACK = 0x00000100;
- pub const LINGER = 0x00000200;
+// /system/develop/headers/posix/poll.h
- pub const SNDBUF = 0x40000001;
- pub const SNDLOWAT = 0x40000002;
- pub const SNDTIMEO = 0x40000003;
- pub const RCVBUF = 0x40000004;
- pub const RCVLOWAT = 0x40000005;
- pub const RCVTIMEO = 0x40000006;
- pub const ERROR = 0x40000007;
- pub const TYPE = 0x40000008;
- pub const NONBLOCK = 0x40000009;
- pub const BINDTODEVICE = 0x4000000a;
- pub const PEERCRED = 0x4000000b;
-};
+pub const nfds_t = usize;
-pub const SOL = struct {
- pub const SOCKET = -1;
+pub const pollfd = extern struct {
+ fd: i32,
+ events: i16,
+ revents: i16,
};
-pub const PF = struct {
- pub const UNSPEC = AF.UNSPEC;
- pub const INET = AF.INET;
- pub const ROUTE = AF.ROUTE;
- pub const LINK = AF.LINK;
- pub const INET6 = AF.INET6;
- pub const LOCAL = AF.LOCAL;
- pub const UNIX = AF.UNIX;
- pub const BLUETOOTH = AF.BLUETOOTH;
-};
+pub const POLL = struct {
+ /// any readable data available
+ pub const IN = 0x0001;
+ /// file descriptor is writeable
+ pub const OUT = 0x0002;
+ pub const RDNORM = IN;
+ pub const WRNORM = OUT;
+ /// priority readable data
+ pub const RDBAND = 0x0008;
+ /// priority data can be written
+ pub const WRBAND = 0x0010;
+ /// high priority readable data
+ pub const PRI = 0x0020;
-pub const AF = struct {
- pub const UNSPEC = 0;
- pub const INET = 1;
- pub const APPLETALK = 2;
- pub const ROUTE = 3;
- pub const LINK = 4;
- pub const INET6 = 5;
- pub const DLI = 6;
- pub const IPX = 7;
- pub const NOTIFY = 8;
- pub const LOCAL = 9;
- pub const UNIX = LOCAL;
- pub const BLUETOOTH = 10;
- pub const MAX = 11;
+ /// errors pending
+ pub const ERR = 0x0004;
+ /// disconnected
+ pub const HUP = 0x0080;
+ /// invalid file descriptor
+ pub const NVAL = 0x1000;
};
-pub const DT = struct {};
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-pub const EVFILT_READ = -1;
-pub const EVFILT_WRITE = -2;
-
-/// attached to aio requests
-pub const EVFILT_AIO = -3;
+// /system/develop/headers/posix/signal.h
-/// attached to vnodes
-pub const EVFILT_VNODE = -4;
+pub const sigset_t = u64;
+pub const empty_sigset: sigset_t = 0;
+pub const filled_sigset = ~@as(sigset_t, 0);
-/// attached to struct proc
-pub const EVFILT_PROC = -5;
+pub const SIG = struct {
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
-/// attached to struct proc
-pub const EVFILT_SIGNAL = -6;
+ pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
-/// timers
-pub const EVFILT_TIMER = -7;
+ pub const HUP = 1;
+ pub const INT = 2;
+ pub const QUIT = 3;
+ pub const ILL = 4;
+ pub const CHLD = 5;
+ pub const ABRT = 6;
+ pub const IOT = ABRT;
+ pub const PIPE = 7;
+ pub const FPE = 8;
+ pub const KILL = 9;
+ pub const STOP = 10;
+ pub const SEGV = 11;
+ pub const CONT = 12;
+ pub const TSTP = 13;
+ pub const ALRM = 14;
+ pub const TERM = 15;
+ pub const TTIN = 16;
+ pub const TTOU = 17;
+ pub const USR1 = 18;
+ pub const USR2 = 19;
+ pub const WINCH = 20;
+ pub const KILLTHR = 21;
+ pub const TRAP = 22;
+ pub const POLL = 23;
+ pub const PROF = 24;
+ pub const SYS = 25;
+ pub const URG = 26;
+ pub const VTALRM = 27;
+ pub const XCPU = 28;
+ pub const XFSZ = 29;
+ pub const BUS = 30;
+ pub const RESERVED1 = 31;
+ pub const RESERVED2 = 32;
-/// Process descriptors
-pub const EVFILT_PROCDESC = -8;
+ pub const BLOCK = 1;
+ pub const UNBLOCK = 2;
+ pub const SETMASK = 3;
+};
-/// Filesystem events
-pub const EVFILT_FS = -9;
+pub const siginfo_t = extern struct {
+ signo: i32,
+ code: i32,
+ errno: i32,
-pub const EVFILT_LIO = -10;
+ pid: pid_t,
+ uid: uid_t,
+ addr: *allowzero anyopaque,
+};
-/// User events
-pub const EVFILT_USER = -11;
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = extern struct {
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
-/// Sendfile events
-pub const EVFILT_SENDFILE = -12;
+ /// signal handler
+ handler: extern union {
+ handler: handler_fn,
+ sigaction: sigaction_fn,
+ },
-pub const EVFILT_EMPTY = -13;
+ /// signal mask to apply
+ mask: sigset_t,
-pub const T = struct {
- pub const CGETA = 0x8000;
- pub const CSETA = 0x8001;
- pub const CSETAF = 0x8002;
- pub const CSETAW = 0x8003;
- pub const CWAITEVENT = 0x8004;
- pub const CSBRK = 0x8005;
- pub const CFLSH = 0x8006;
- pub const CXONC = 0x8007;
- pub const CQUERYCONNECTED = 0x8008;
- pub const CGETBITS = 0x8009;
- pub const CSETDTR = 0x8010;
- pub const CSETRTS = 0x8011;
- pub const IOCGWINSZ = 0x8012;
- pub const IOCSWINSZ = 0x8013;
- pub const CVTIME = 0x8014;
- pub const IOCGPGRP = 0x8015;
- pub const IOCSPGRP = 0x8016;
- pub const IOCSCTTY = 0x8017;
- pub const IOCMGET = 0x8018;
- pub const IOCMSET = 0x8019;
- pub const IOCSBRK = 0x8020;
- pub const IOCCBRK = 0x8021;
- pub const IOCMBIS = 0x8022;
- pub const IOCMBIC = 0x8023;
- pub const IOCGSID = 0x8024;
+ /// see signal options
+ flags: i32,
- pub const FIONREAD = 0xbe000001;
- pub const FIONBIO = 0xbe000000;
+ /// will be passed to the signal handler, BeOS extension
+ userdata: *allowzero anyopaque = undefined,
};
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
+pub const SA = struct {
+ pub const NOCLDSTOP = 0x01;
+ pub const NOCLDWAIT = 0x02;
+ pub const RESETHAND = 0x04;
+ pub const NODEFER = 0x08;
+ pub const RESTART = 0x10;
+ pub const ONSTACK = 0x20;
+ pub const SIGINFO = 0x40;
+ pub const NOMASK = NODEFER;
+ pub const STACK = ONSTACK;
+ pub const ONESHOT = RESETHAND;
};
-const B_POSIX_ERROR_BASE = -2147454976;
+pub const SS = struct {
+ pub const ONSTACK = 0x1;
+ pub const DISABLE = 0x2;
+};
-pub const E = enum(i32) {
- @"2BIG" = B_POSIX_ERROR_BASE + 1,
- CHILD = B_POSIX_ERROR_BASE + 2,
- DEADLK = B_POSIX_ERROR_BASE + 3,
- FBIG = B_POSIX_ERROR_BASE + 4,
- MLINK = B_POSIX_ERROR_BASE + 5,
- NFILE = B_POSIX_ERROR_BASE + 6,
- NODEV = B_POSIX_ERROR_BASE + 7,
- NOLCK = B_POSIX_ERROR_BASE + 8,
- NOSYS = B_POSIX_ERROR_BASE + 9,
- NOTTY = B_POSIX_ERROR_BASE + 10,
- NXIO = B_POSIX_ERROR_BASE + 11,
- SPIPE = B_POSIX_ERROR_BASE + 12,
- SRCH = B_POSIX_ERROR_BASE + 13,
- FPOS = B_POSIX_ERROR_BASE + 14,
- SIGPARM = B_POSIX_ERROR_BASE + 15,
- DOM = B_POSIX_ERROR_BASE + 16,
- RANGE = B_POSIX_ERROR_BASE + 17,
- PROTOTYPE = B_POSIX_ERROR_BASE + 18,
- PROTONOSUPPORT = B_POSIX_ERROR_BASE + 19,
- PFNOSUPPORT = B_POSIX_ERROR_BASE + 20,
- AFNOSUPPORT = B_POSIX_ERROR_BASE + 21,
- ADDRINUSE = B_POSIX_ERROR_BASE + 22,
- ADDRNOTAVAIL = B_POSIX_ERROR_BASE + 23,
- NETDOWN = B_POSIX_ERROR_BASE + 24,
- NETUNREACH = B_POSIX_ERROR_BASE + 25,
- NETRESET = B_POSIX_ERROR_BASE + 26,
- CONNABORTED = B_POSIX_ERROR_BASE + 27,
- CONNRESET = B_POSIX_ERROR_BASE + 28,
- ISCONN = B_POSIX_ERROR_BASE + 29,
- NOTCONN = B_POSIX_ERROR_BASE + 30,
- SHUTDOWN = B_POSIX_ERROR_BASE + 31,
- CONNREFUSED = B_POSIX_ERROR_BASE + 32,
- HOSTUNREACH = B_POSIX_ERROR_BASE + 33,
- NOPROTOOPT = B_POSIX_ERROR_BASE + 34,
- NOBUFS = B_POSIX_ERROR_BASE + 35,
- INPROGRESS = B_POSIX_ERROR_BASE + 36,
- ALREADY = B_POSIX_ERROR_BASE + 37,
- ILSEQ = B_POSIX_ERROR_BASE + 38,
- NOMSG = B_POSIX_ERROR_BASE + 39,
- STALE = B_POSIX_ERROR_BASE + 40,
- OVERFLOW = B_POSIX_ERROR_BASE + 41,
- MSGSIZE = B_POSIX_ERROR_BASE + 42,
- OPNOTSUPP = B_POSIX_ERROR_BASE + 43,
- NOTSOCK = B_POSIX_ERROR_BASE + 44,
- HOSTDOWN = B_POSIX_ERROR_BASE + 45,
- BADMSG = B_POSIX_ERROR_BASE + 46,
- CANCELED = B_POSIX_ERROR_BASE + 47,
- DESTADDRREQ = B_POSIX_ERROR_BASE + 48,
- DQUOT = B_POSIX_ERROR_BASE + 49,
- IDRM = B_POSIX_ERROR_BASE + 50,
- MULTIHOP = B_POSIX_ERROR_BASE + 51,
- NODATA = B_POSIX_ERROR_BASE + 52,
- NOLINK = B_POSIX_ERROR_BASE + 53,
- NOSR = B_POSIX_ERROR_BASE + 54,
- NOSTR = B_POSIX_ERROR_BASE + 55,
- NOTSUP = B_POSIX_ERROR_BASE + 56,
- PROTO = B_POSIX_ERROR_BASE + 57,
- TIME = B_POSIX_ERROR_BASE + 58,
- TXTBSY = B_POSIX_ERROR_BASE + 59,
- NOATTR = B_POSIX_ERROR_BASE + 60,
- NOTRECOVERABLE = B_POSIX_ERROR_BASE + 61,
- OWNERDEAD = B_POSIX_ERROR_BASE + 62,
+pub const MINSIGSTKSZ = 8192;
+pub const SIGSTKSZ = 16384;
- ACCES = -0x7ffffffe, // Permission denied
- INTR = -0x7ffffff6, // Interrupted system call
- IO = -0x7fffffff, // Input/output error
- BUSY = -0x7ffffff2, // Device busy
- FAULT = -0x7fffecff, // Bad address
- TIMEDOUT = -2147483639, // Operation timed out
- AGAIN = -0x7ffffff5,
- BADF = -0x7fffa000, // Bad file descriptor
- EXIST = -0x7fff9ffe, // File exists
- INVAL = -0x7ffffffb, // Invalid argument
- NAMETOOLONG = -2147459068, // File name too long
- NOENT = -0x7fff9ffd, // No such file or directory
- PERM = -0x7ffffff1, // Operation not permitted
- NOTDIR = -0x7fff9ffb, // Not a directory
- ISDIR = -0x7fff9ff7, // Is a directory
- NOTEMPTY = -2147459066, // Directory not empty
- NOSPC = -0x7fff9ff9, // No space left on device
- ROFS = -0x7fff9ff8, // Read-only filesystem
- MFILE = -0x7fff9ff6, // Too many open files
- XDEV = -0x7fff9ff5, // Cross-device link
- NOEXEC = -0x7fffecfe, // Exec format error
- PIPE = -0x7fff9ff3, // Broken pipe
- NOMEM = -0x80000000, // Cannot allocate memory
- LOOP = -2147459060, // Too many levels of symbolic links
- SUCCESS = 0,
- _,
+pub const stack_t = extern struct {
+ sp: [*]u8,
+ size: isize,
+ flags: i32,
};
-pub const S = struct {
- pub const IFMT = 0o170000;
- pub const IFSOCK = 0o140000;
- pub const IFLNK = 0o120000;
- pub const IFREG = 0o100000;
- pub const IFBLK = 0o060000;
- pub const IFDIR = 0o040000;
- pub const IFCHR = 0o020000;
- pub const IFIFO = 0o010000;
- pub const INDEX_DIR = 0o4000000000;
-
- pub const IUMSK = 0o7777;
- pub const ISUID = 0o4000;
- pub const ISGID = 0o2000;
- pub const ISVTX = 0o1000;
- pub const IRWXU = 0o700;
- pub const IRUSR = 0o400;
- pub const IWUSR = 0o200;
- pub const IXUSR = 0o100;
- pub const IRWXG = 0o070;
- pub const IRGRP = 0o040;
- pub const IWGRP = 0o020;
- pub const IXGRP = 0o010;
- pub const IRWXO = 0o007;
- pub const IROTH = 0o004;
- pub const IWOTH = 0o002;
- pub const IXOTH = 0o001;
+pub const NSIG = 65;
- pub fn ISREG(m: u32) bool {
- return m & IFMT == IFREG;
- }
+pub const mcontext_t = vregs;
- pub fn ISLNK(m: u32) bool {
- return m & IFMT == IFLNK;
- }
+pub const ucontext_t = extern struct {
+ link: ?*ucontext_t,
+ sigmask: sigset_t,
+ stack: stack_t,
+ mcontext: mcontext_t,
+};
- pub fn ISBLK(m: u32) bool {
- return m & IFMT == IFBLK;
- }
+// /system/develop/headers/posix/sys/stat.h
- pub fn ISDIR(m: u32) bool {
- return m & IFMT == IFDIR;
- }
+pub const Stat = extern struct {
+ dev: dev_t,
+ ino: ino_t,
+ mode: mode_t,
+ nlink: nlink_t,
+ uid: uid_t,
+ gid: gid_t,
+ size: off_t,
+ rdev: dev_t,
+ blksize: blksize_t,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ crtim: timespec,
+ type: u32,
+ blocks: blkcnt_t,
- pub fn ISCHR(m: u32) bool {
- return m & IFMT == IFCHR;
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
}
-
- pub fn ISFIFO(m: u32) bool {
- return m & IFMT == IFIFO;
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
}
-
- pub fn ISSOCK(m: u32) bool {
- return m & IFMT == IFSOCK;
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
}
-
- pub fn ISINDEX(m: u32) bool {
- return m & INDEX_DIR == INDEX_DIR;
+ pub fn birthtime(self: @This()) timespec {
+ return self.crtim;
}
};
-pub const HOST_NAME_MAX = 255;
+// /system/develop/headers/posix/sys/types.h
-pub const addrinfo = extern struct {
- flags: i32,
- family: i32,
- socktype: i32,
- protocol: i32,
- addrlen: socklen_t,
- canonname: ?[*:0]u8,
- addr: ?*sockaddr,
- next: ?*addrinfo,
-};
+pub const blkcnt_t = i64;
+pub const blksize_t = i32;
+pub const fsblkcnt_t = i64;
+pub const fsfilcnt_t = i64;
+pub const off_t = i64;
+pub const ino_t = i64;
+pub const cnt_t = i32;
+pub const dev_t = i32;
+pub const pid_t = i32;
+pub const id_t = i32;
-pub const IPPROTO = struct {
- pub const IP = 0;
- pub const HOPOPTS = 0;
- pub const ICMP = 1;
- pub const IGMP = 2;
- pub const TCP = 6;
- pub const UDP = 17;
- pub const IPV6 = 41;
- pub const ROUTING = 43;
- pub const FRAGMENT = 44;
- pub const ESP = 50;
- pub const AH = 51;
- pub const ICMPV6 = 58;
- pub const NONE = 59;
- pub const DSTOPTS = 60;
- pub const ETHERIP = 97;
- pub const RAW = 255;
- pub const MAX = 256;
-};
+pub const uid_t = u32;
+pub const gid_t = u32;
+pub const mode_t = u32;
+pub const umode_t = u32;
+pub const nlink_t = i32;
-pub const rlimit_resource = enum(c_int) {
- CORE = 0,
- CPU = 1,
- DATA = 2,
- FSIZE = 3,
- NOFILE = 4,
- STACK = 5,
- AS = 6,
- NOVMON = 7,
- _,
-};
+pub const clockid_t = i32;
+pub const timer_t = *opaque {};
-pub const rlim_t = i64;
+// /system/develop/headers/posix/time.h
-pub const RLIM = struct {
- /// No limit
- pub const INFINITY: rlim_t = (1 << 63) - 1;
+pub const clock_t = i32;
+pub const suseconds_t = i32;
+pub const useconds_t = u32;
- pub const SAVED_MAX = INFINITY;
- pub const SAVED_CUR = INFINITY;
-};
+pub const time_t = isize;
-pub const rlimit = extern struct {
- /// Soft limit
- cur: rlim_t,
- /// Hard limit
- max: rlim_t,
-};
+pub const CLOCKS_PER_SEC = 1_000_000;
+pub const CLK_TCK = CLOCKS_PER_SEC;
+pub const TIME_UTC = 1;
-pub const SHUT = struct {
- pub const RD = 0;
- pub const WR = 1;
- pub const RDWR = 2;
+pub const CLOCK = struct {
+ /// system-wide monotonic clock (aka system time)
+ pub const MONOTONIC: clockid_t = 0;
+ /// system-wide real time clock
+ pub const REALTIME: clockid_t = -1;
+ /// clock measuring the used CPU time of the current process
+ pub const PROCESS_CPUTIME_ID: clockid_t = -2;
+ /// clock measuring the used CPU time of the current thread
+ pub const THREAD_CPUTIME_ID: clockid_t = -3;
};
-// TODO fill out if needed
-pub const directory_which = enum(c_int) {
- B_USER_SETTINGS_DIRECTORY = 0xbbe,
+pub const timespec = extern struct {
+ /// seconds
+ tv_sec: time_t,
+ /// and nanoseconds
+ tv_nsec: isize,
+};
- _,
+pub const itimerspec = extern struct {
+ interval: timespec,
+ value: timespec,
};
-pub const MSG_NOSIGNAL = 0x0800;
+// /system/develop/headers/private/system/syscalls.h
+
+pub extern "root" fn _kern_get_current_team() team_id;
+pub extern "root" fn _kern_open_dir(fd: fd_t, path: [*:0]const u8) fd_t;
+pub extern "root" fn _kern_read_dir(fd: fd_t, buffer: [*]u8, bufferSize: usize, maxCount: u32) isize;
+pub extern "root" fn _kern_rewind_dir(fd: fd_t) status_t;
+pub extern "root" fn _kern_read_stat(fd: fd_t, path: [*:0]const u8, traverseLink: bool, stat: *Stat, statSize: usize) status_t;
diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig
index c3ac3e22aa..b1cc4fc095 100644
--- a/lib/std/crypto/Certificate.zig
+++ b/lib/std/crypto/Certificate.zig
@@ -772,7 +772,7 @@ fn verifyRsa(
Hash.hash(message, &msg_hashed, .{});
switch (modulus.len) {
- inline 128, 256, 512 => |modulus_len| {
+ inline 128, 256, 384, 512 => |modulus_len| {
const ps_len = modulus_len - (hash_der.len + msg_hashed.len) - 3;
const em: [modulus_len]u8 =
[2]u8{ 0, 1 } ++
diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig
index 7e118afb26..3e979175d8 100644
--- a/lib/std/crypto/benchmark.zig
+++ b/lib/std/crypto/benchmark.zig
@@ -131,7 +131,12 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
return throughput;
}
-const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
+const signatures = [_]Crypto{
+ Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
+ Crypto{ .ty = crypto.sign.ecdsa.EcdsaP256Sha256, .name = "ecdsa-p256" },
+ Crypto{ .ty = crypto.sign.ecdsa.EcdsaP384Sha384, .name = "ecdsa-p384" },
+ Crypto{ .ty = crypto.sign.ecdsa.EcdsaSecp256k1Sha256, .name = "ecdsa-secp256k1" },
+};
pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
const msg = [_]u8{0} ** 64;
diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig
index 70362470c3..b2751ce20a 100644
--- a/lib/std/crypto/ecdsa.zig
+++ b/lib/std/crypto/ecdsa.zig
@@ -4,6 +4,7 @@ const crypto = std.crypto;
const fmt = std.fmt;
const io = std.io;
const mem = std.mem;
+const sha3 = crypto.hash.sha3;
const testing = std.testing;
const EncodingError = crypto.errors.EncodingError;
@@ -26,7 +27,11 @@ pub const EcdsaSecp256k1Sha256oSha256 = Ecdsa(crypto.ecc.Secp256k1, crypto.hash.
/// Elliptic Curve Digital Signature Algorithm (ECDSA).
pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
- const Hmac = crypto.auth.hmac.Hmac(Hash);
+ const Prf = switch (Hash) {
+ sha3.Shake128 => sha3.KMac128,
+ sha3.Shake256 => sha3.KMac256,
+ else => crypto.auth.hmac.Hmac(Hash),
+ };
return struct {
/// Length (in bytes) of optional random bytes, for non-deterministic signatures.
@@ -350,22 +355,22 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
if (noise) |n| @memcpy(m_z, &n);
@memcpy(m_x, &secret_key);
@memcpy(m_h, &h);
- Hmac.create(&k, &m, &k);
- Hmac.create(m_v, m_v, &k);
+ Prf.create(&k, &m, &k);
+ Prf.create(m_v, m_v, &k);
m_i.* = 0x01;
- Hmac.create(&k, &m, &k);
- Hmac.create(m_v, m_v, &k);
+ Prf.create(&k, &m, &k);
+ Prf.create(m_v, m_v, &k);
while (true) {
var t_off: usize = 0;
while (t_off < t.len) : (t_off += m_v.len) {
const t_end = @min(t_off + m_v.len, t.len);
- Hmac.create(m_v, m_v, &k);
+ Prf.create(m_v, m_v, &k);
@memcpy(t[t_off..t_end], m_v[0 .. t_end - t_off]);
}
if (Curve.scalar.Scalar.fromBytes(t, .big)) |s| return s else |_| {}
m_i.* = 0x00;
- Hmac.create(&k, m[0 .. m_v.len + 1], &k);
- Hmac.create(m_v, m_v, &k);
+ Prf.create(&k, m[0 .. m_v.len + 1], &k);
+ Prf.create(m_v, m_v, &k);
}
}
};
diff --git a/lib/std/crypto/keccak_p.zig b/lib/std/crypto/keccak_p.zig
index d04373269e..352172a1f6 100644
--- a/lib/std/crypto/keccak_p.zig
+++ b/lib/std/crypto/keccak_p.zig
@@ -195,7 +195,7 @@ pub fn KeccakF(comptime f: u11) type {
}
/// A generic Keccak-P state.
-pub fn State(comptime f: u11, comptime capacity: u11, comptime delim: u8, comptime rounds: u5) type {
+pub fn State(comptime f: u11, comptime capacity: u11, comptime rounds: u5) type {
comptime assert(f > 200 and f <= 1600 and f % 200 == 0); // invalid state size
comptime assert(capacity < f and capacity % 8 == 0); // invalid capacity size
@@ -207,6 +207,9 @@ pub fn State(comptime f: u11, comptime capacity: u11, comptime delim: u8, compti
/// Keccak does not have any options.
pub const Options = struct {};
+ /// The input delimiter.
+ delim: u8,
+
offset: usize = 0,
buf: [rate]u8 = undefined,
@@ -238,10 +241,28 @@ pub fn State(comptime f: u11, comptime capacity: u11, comptime delim: u8, compti
}
}
+ /// Initialize the state from a slice of bytes.
+ pub fn init(bytes: [f / 8]u8) Self {
+ return .{ .st = KeccakF(f).init(bytes) };
+ }
+
+ /// Permute the state
+ pub fn permute(self: *Self) void {
+ self.st.permuteR(rounds);
+ self.offset = 0;
+ }
+
+ /// Align the input to the rate boundary.
+ pub fn fillBlock(self: *Self) void {
+ self.st.addBytes(self.buf[0..self.offset]);
+ self.st.permuteR(rounds);
+ self.offset = 0;
+ }
+
/// Mark the end of the input.
pub fn pad(self: *Self) void {
self.st.addBytes(self.buf[0..self.offset]);
- self.st.addByte(delim, self.offset);
+ self.st.addByte(self.delim, self.offset);
self.st.addByte(0x80, rate - 1);
self.st.permuteR(rounds);
self.offset = 0;
diff --git a/lib/std/crypto/pcurves/p256/p256_64.zig b/lib/std/crypto/pcurves/p256/p256_64.zig
index e8dbaead33..f3d38ca3e6 100644
--- a/lib/std/crypto/pcurves/p256/p256_64.zig
+++ b/lib/std/crypto/pcurves/p256/p256_64.zig
@@ -73,12 +73,9 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -95,12 +92,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig
index 152c2b8787..736a3ea8b7 100644
--- a/lib/std/crypto/pcurves/p256/p256_scalar_64.zig
+++ b/lib/std/crypto/pcurves/p256/p256_scalar_64.zig
@@ -73,12 +73,9 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -95,12 +92,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/pcurves/p384/p384_64.zig b/lib/std/crypto/pcurves/p384/p384_64.zig
index f25a7d65b5..e1419e7c81 100644
--- a/lib/std/crypto/pcurves/p384/p384_64.zig
+++ b/lib/std/crypto/pcurves/p384/p384_64.zig
@@ -42,12 +42,9 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -64,12 +61,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig
index fc787ba7b9..68a0a0ca2f 100644
--- a/lib/std/crypto/pcurves/p384/p384_scalar_64.zig
+++ b/lib/std/crypto/pcurves/p384/p384_scalar_64.zig
@@ -42,12 +42,9 @@ pub const NonMontgomeryDomainFieldElement = [6]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -64,12 +61,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig
index ae3e97c619..1c69b90eea 100644
--- a/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig
+++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_64.zig
@@ -42,12 +42,9 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -64,12 +61,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig
index 12c833bb33..97bf5f0a45 100644
--- a/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig
+++ b/lib/std/crypto/pcurves/secp256k1/secp256k1_scalar_64.zig
@@ -42,12 +42,9 @@ pub const NonMontgomeryDomainFieldElement = [4]u64;
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @addWithOverflow(arg2, arg3);
- const ov2 = @addWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) +% arg3 +% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function subborrowxU64 is a subtraction with borrow.
@@ -64,12 +61,9 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
/// out1: [0x0 ~> 0xffffffffffffffff]
/// out2: [0x0 ~> 0x1]
inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void {
- @setRuntimeSafety(mode == .Debug);
-
- const ov1 = @subWithOverflow(arg2, arg3);
- const ov2 = @subWithOverflow(ov1[0], arg1);
- out1.* = ov2[0];
- out2.* = ov1[1] | ov2[1];
+ const x = @as(u128, arg2) -% arg3 -% arg1;
+ out1.* = @truncate(x);
+ out2.* = @truncate(x >> 64);
}
/// The function mulxU64 is a multiplication, returning the full double-width result.
diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig
index 8fa76a48bf..e75dcb7b79 100644
--- a/lib/std/crypto/sha3.zig
+++ b/lib/std/crypto/sha3.zig
@@ -18,11 +18,20 @@ pub const Keccak_512 = @compileError("Deprecated: use `Keccak512` instead");
pub const Shake128 = Shake(128);
pub const Shake256 = Shake(256);
+pub const CShake128 = CShake(128, null);
+pub const CShake256 = CShake(256, null);
+
+pub const KMac128 = KMac(128);
+pub const KMac256 = KMac(256);
+
+pub const TupleHash128 = TupleHash(128);
+pub const TupleHash256 = TupleHash(256);
+
/// TurboSHAKE128 is a XOF (a secure hash function with a variable output length), with a 128 bit security level.
/// It is based on the same permutation as SHA3 and SHAKE128, but which much higher performance.
/// The delimiter is 0x1f by default, but can be changed for context-separation.
/// For a protocol that uses both KangarooTwelve and TurboSHAKE128, it is recommended to avoid using 0x06, 0x07 or 0x0b for the delimiter.
-pub fn TurboShake128(comptime delim: ?u7) type {
+pub fn TurboShake128(delim: ?u7) type {
return TurboShake(128, delim);
}
@@ -34,27 +43,26 @@ pub fn TurboShake256(comptime delim: ?u7) type {
}
/// A generic Keccak hash function.
-pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime delim: u8, comptime rounds: u5) type {
+pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim: u8, comptime rounds: u5) type {
comptime assert(output_bits > 0 and output_bits * 2 < f and output_bits % 8 == 0); // invalid output length
- const State = KeccakState(f, output_bits * 2, delim, rounds);
+ const State = KeccakState(f, output_bits * 2, rounds);
return struct {
const Self = @This();
- st: State = .{},
+ st: State,
/// The output length, in bytes.
pub const digest_length = output_bits / 8;
/// The block length, or rate, in bytes.
pub const block_length = State.rate;
- /// Keccak does not have any options.
- pub const Options = struct {};
+ /// The delimiter can be overwritten in the options.
+ pub const Options = struct { delim: u8 = default_delim };
/// Initialize a Keccak hash function.
pub fn init(options: Options) Self {
- _ = options;
- return Self{};
+ return Self{ .st = .{ .delim = options.delim } };
}
/// Hash a slice of bytes.
@@ -105,29 +113,28 @@ pub fn TurboShake(comptime security_level: u11, comptime delim: ?u7) type {
return ShakeLike(security_level, d, 12);
}
-fn ShakeLike(comptime security_level: u11, comptime delim: u8, comptime rounds: u5) type {
+fn ShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime rounds: u5) type {
const f = 1600;
- const State = KeccakState(f, security_level * 2, delim, rounds);
+ const State = KeccakState(f, security_level * 2, rounds);
return struct {
const Self = @This();
- st: State = .{},
+ st: State,
buf: [State.rate]u8 = undefined,
offset: usize = 0,
padded: bool = false,
/// The recommended output length, in bytes.
- pub const digest_length = security_level / 2;
+ pub const digest_length = security_level / 8 * 2;
/// The block length, or rate, in bytes.
pub const block_length = State.rate;
- /// Keccak does not have any options.
- pub const Options = struct {};
+ /// The delimiter can be overwritten in the options.
+ pub const Options = struct { delim: u8 = default_delim };
/// Initialize a SHAKE extensible hash function.
pub fn init(options: Options) Self {
- _ = options;
- return Self{};
+ return Self{ .st = .{ .delim = options.delim } };
}
/// Hash a slice of bytes.
@@ -182,6 +189,11 @@ fn ShakeLike(comptime security_level: u11, comptime delim: u8, comptime rounds:
self.st.st.clear(0, State.rate);
}
+ /// Align the input to a block boundary.
+ pub fn fillBlock(self: *Self) void {
+ self.st.fillBlock();
+ }
+
pub const Error = error{};
pub const Writer = std.io.Writer(*Self, Error, write);
@@ -196,6 +208,338 @@ fn ShakeLike(comptime security_level: u11, comptime delim: u8, comptime rounds:
};
}
+/// The cSHAKE extendable output hash function.
+/// cSHAKE is similar to SHAKE, but in addition to the input message, it also takes an optional context (aka customization string).
+pub fn CShake(comptime security_level: u11, comptime fname: ?[]const u8) type {
+ return CShakeLike(security_level, 0x04, 24, fname);
+}
+
+fn CShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime rounds: u5, comptime fname: ?[]const u8) type {
+ return struct {
+ const Shaker = ShakeLike(security_level, default_delim, rounds);
+ shaker: Shaker,
+
+ /// The recommended output length, in bytes.
+ pub const digest_length = Shaker.digest_length;
+ /// The block length, or rate, in bytes.
+ pub const block_length = Shaker.block_length;
+
+ /// cSHAKE options can include a context string.
+ pub const Options = struct { context: ?[]const u8 = null };
+
+ const Self = @This();
+
+ /// Initialize a SHAKE extensible hash function.
+ pub fn init(options: Options) Self {
+ if (fname == null and options.context == null) {
+ return Self{ .shaker = Shaker.init(.{ .delim = 0x1f }) };
+ }
+ var shaker = Shaker.init(.{});
+ comptime assert(Shaker.block_length % 8 == 0);
+ const encoded_rate_len = NistLengthEncoding.encode(.left, block_length / 8);
+ shaker.update(encoded_rate_len.slice());
+ const encoded_zero = comptime NistLengthEncoding.encode(.left, 0);
+ if (fname) |name| {
+ const encoded_fname_len = comptime NistLengthEncoding.encode(.left, name.len);
+ const encoded_fname = comptime encoded_fname_len.slice() ++ name;
+ shaker.update(encoded_fname);
+ } else {
+ shaker.update(encoded_zero.slice());
+ }
+ if (options.context) |context| {
+ const encoded_context_len = NistLengthEncoding.encode(.left, context.len);
+ shaker.update(encoded_context_len.slice());
+ shaker.update(context);
+ } else {
+ shaker.update(encoded_zero.slice());
+ }
+ shaker.st.fillBlock();
+ return Self{ .shaker = shaker };
+ }
+
+ /// Hash a slice of bytes.
+ /// `out` can be any length.
+ pub fn hash(bytes: []const u8, out: []u8, options: Options) void {
+ var st = Self.init(options);
+ st.update(bytes);
+ st.squeeze(out);
+ }
+
+ /// Absorb a slice of bytes into the state.
+ pub fn update(self: *Self, bytes: []const u8) void {
+ self.shaker.update(bytes);
+ }
+
+ /// Squeeze a slice of bytes from the state.
+ /// `out` can be any length, and the function can be called multiple times.
+ pub fn squeeze(self: *Self, out: []u8) void {
+ self.shaker.squeeze(out);
+ }
+
+ /// Return the hash of the absorbed bytes.
+ /// `out` can be of any length, but the function must not be called multiple times (use `squeeze` for that purpose instead).
+ pub fn final(self: *Self, out: []u8) void {
+ self.shaker.final(out);
+ }
+
+ /// Align the input to a block boundary.
+ pub fn fillBlock(self: *Self) void {
+ self.shaker.fillBlock();
+ }
+
+ pub const Error = error{};
+ pub const Writer = std.io.Writer(*Self, Error, write);
+
+ fn write(self: *Self, bytes: []const u8) Error!usize {
+ self.update(bytes);
+ return bytes.len;
+ }
+
+ pub fn writer(self: *Self) Writer {
+ return .{ .context = self };
+ }
+ };
+}
+
+/// The KMAC extendable output authentication function.
+/// KMAC is a keyed version of the cSHAKE function, with an optional context.
+/// It can be used as an SHA-3 based alternative to HMAC, as well as a generic keyed XoF (extendable output function).
+pub fn KMac(comptime security_level: u11) type {
+ return KMacLike(security_level, 0x04, 24);
+}
+
+fn KMacLike(comptime security_level: u11, comptime default_delim: u8, comptime rounds: u5) type {
+ const CShaker = CShakeLike(security_level, default_delim, rounds, "KMAC");
+
+ return struct {
+ const Self = @This();
+
+ /// The recommended output length, in bytes.
+ pub const mac_length = CShaker.digest_length;
+ /// The minimum output length, in bytes.
+ pub const mac_length_min = 4;
+ /// The recommended key length, in bytes.
+ pub const key_length = security_level / 8;
+ /// The minimum key length, in bytes.
+ pub const key_length_min = 0;
+ /// The block length, or rate, in bytes.
+ pub const block_length = CShaker.block_length;
+
+ cshaker: CShaker,
+ xof_mode: bool = false,
+
+ /// KMAC options can include a context string.
+ pub const Options = struct {
+ context: ?[]const u8 = null,
+ };
+
+ /// Initialize a state for the KMAC function, with an optional context and an arbitrary-long key.
+ /// If the context and key are going to be reused, the structure can be initialized once, and cloned for each message.
+ /// This is more efficient than reinitializing the state for each message at the cost of a small amount of memory.
+ pub fn initWithOptions(key: []const u8, options: Options) Self {
+ var cshaker = CShaker.init(.{ .context = options.context });
+ const encoded_rate_len = NistLengthEncoding.encode(.left, block_length / 8);
+ cshaker.update(encoded_rate_len.slice());
+ const encoded_key_len = NistLengthEncoding.encode(.left, key.len);
+ cshaker.update(encoded_key_len.slice());
+ cshaker.update(key);
+ cshaker.fillBlock();
+ return Self{
+ .cshaker = cshaker,
+ };
+ }
+
+ /// Initialize a state for the KMAC function.
+ /// If the context and key are going to be reused, the structure can be initialized once, and cloned for each message.
+ /// This is more efficient than reinitializing the state for each message at the cost of a small amount of memory.
+ pub fn init(key: []const u8) Self {
+ return initWithOptions(key, .{});
+ }
+
+ /// Add data to the state.
+ pub fn update(self: *Self, b: []const u8) void {
+ self.cshaker.update(b);
+ }
+
+ /// Return an authentication tag for the current state.
+ pub fn final(self: *Self, out: []u8) void {
+ const encoded_out_len = NistLengthEncoding.encode(.right, out.len);
+ self.update(encoded_out_len.slice());
+ self.cshaker.final(out);
+ }
+
+ /// Squeeze a slice of bytes from the state.
+ /// `out` can be any length, and the function can be called multiple times.
+ pub fn squeeze(self: *Self, out: []u8) void {
+ if (!self.xof_mode) {
+ const encoded_out_len = comptime NistLengthEncoding.encode(.right, 0);
+ self.update(encoded_out_len.slice());
+ self.xof_mode = true;
+ }
+ self.cshaker.squeeze(out);
+ }
+
+ /// Return an authentication tag for a message and a key, with an optional context.
+ pub fn createWithOptions(out: []u8, msg: []const u8, key: []const u8, options: Options) void {
+ var ctx = Self.initWithOptions(key, options);
+ ctx.update(msg);
+ ctx.final(out);
+ }
+
+ /// Return an authentication tag for a message and a key.
+ pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
+ var ctx = Self.init(key);
+ ctx.update(msg);
+ ctx.final(out);
+ }
+
+ pub const Error = error{};
+ pub const Writer = std.io.Writer(*Self, Error, write);
+
+ fn write(self: *Self, bytes: []const u8) Error!usize {
+ self.update(bytes);
+ return bytes.len;
+ }
+
+ pub fn writer(self: *Self) Writer {
+ return .{ .context = self };
+ }
+ };
+}
+
+/// The TupleHash extendable output hash function, with domain-separated inputs.
+/// TupleHash is a secure hash function with a variable output length, based on the cSHAKE function.
+/// It is designed for unambiguously hashing tuples of data.
+///
+/// With most hash functions, calling `update("A")` followed by `update("B")`is identical to `update("AB")`.
+/// With TupleHash, this is not the case: `update("A"); update("B")` is different from `update("AB")`.
+///
+/// Any number of inputs can be hashed, and the output depends on individual inputs and their order.
+pub fn TupleHash(comptime security_level: u11) type {
+ return TupleHashLike(security_level, 0x04, 24);
+}
+
+fn TupleHashLike(comptime security_level: u11, comptime default_delim: u8, comptime rounds: u5) type {
+ const CShaker = CShakeLike(security_level, default_delim, rounds, "TupleHash");
+
+ return struct {
+ const Self = @This();
+
+ /// The output length, in bytes.
+ pub const digest_length = CShaker.digest_length;
+ /// The block length, or rate, in bytes.
+ pub const block_length = CShaker.block_length;
+
+ cshaker: CShaker,
+ xof_mode: bool = false,
+
+ /// TupleHash options can include a context string.
+ pub const Options = struct {
+ context: ?[]const u8 = null,
+ };
+
+ /// Initialize a state for the TupleHash function, with an optional context.
+ /// If the context is going to be reused, the structure can be initialized once, and cloned for each message.
+ /// This is more efficient than reinitializing the state for each message at the cost of a small amount of memory.
+ ///
+ /// A key can be optionally added to the context to create a keyed TupleHash function, similar to KMAC.
+ pub fn initWithOptions(options: Options) Self {
+ const cshaker = CShaker.init(.{ .context = options.context });
+ return Self{
+ .cshaker = cshaker,
+ };
+ }
+
+ /// Initialize a state for the MAC function.
+ pub fn init() Self {
+ return initWithOptions(.{});
+ }
+
+ /// Add data to the state, separated from previous updates.
+ pub fn update(self: *Self, b: []const u8) void {
+ const encoded_b_len = NistLengthEncoding.encode(.left, b.len);
+ self.cshaker.update(encoded_b_len.slice());
+ self.cshaker.update(b);
+ }
+
+ /// Return an authentication tag for the current state.
+ pub fn final(self: *Self, out: []u8) void {
+ const encoded_out_len = NistLengthEncoding.encode(.right, out.len);
+ self.cshaker.update(encoded_out_len.slice());
+ self.cshaker.final(out);
+ }
+
+ /// Align the input to a block boundary.
+ pub fn fillBlock(self: *Self) void {
+ self.cshaker.fillBlock();
+ }
+
+ /// Squeeze a slice of bytes from the state.
+ /// `out` can be any length, and the function can be called multiple times.
+ pub fn squeeze(self: *Self, out: []u8) void {
+ if (!self.xof_mode) {
+ const encoded_out_len = comptime NistLengthEncoding.encode(.right, 0);
+ self.update(encoded_out_len.slice());
+ self.xof_mode = true;
+ }
+ self.cshaker.squeeze(out);
+ }
+
+ pub const Error = error{};
+ pub const Writer = std.io.Writer(*Self, Error, write);
+
+ fn write(self: *Self, bytes: []const u8) Error!usize {
+ self.update(bytes);
+ return bytes.len;
+ }
+
+ pub fn writer(self: *Self) Writer {
+ return .{ .context = self };
+ }
+ };
+}
+
+/// The NIST SP 800-185 encoded length format.
+pub const NistLengthEncoding = enum {
+ left,
+ right,
+
+ /// A length encoded according to NIST SP 800-185.
+ pub const Length = struct {
+ /// The size of the encoded value, in bytes.
+ len: usize = 0,
+ /// A buffer to store the encoded length.
+ buf: [@sizeOf(usize) + 1]u8 = undefined,
+
+ /// Return the encoded length as a slice.
+ pub fn slice(self: *const Length) []const u8 {
+ return self.buf[0..self.len];
+ }
+ };
+
+ /// Encode a length according to NIST SP 800-185.
+ pub fn encode(comptime encoding: NistLengthEncoding, len: usize) Length {
+ const len_bits = @bitSizeOf(@TypeOf(len)) - @clz(len) + 3;
+ const len_bytes = std.math.divCeil(usize, len_bits, 8) catch unreachable;
+
+ var res = Length{ .len = len_bytes + 1 };
+ if (encoding == .right) {
+ res.buf[len_bytes] = @intCast(len_bytes);
+ }
+ const end = if (encoding == .right) len_bytes - 1 else len_bytes;
+ res.buf[end] = @truncate(len << 3);
+ var len_ = len >> 5;
+ for (1..len_bytes) |i| {
+ res.buf[end - i] = @truncate(len_);
+ len_ >>= 8;
+ }
+ if (encoding == .left) {
+ res.buf[0] = @intCast(len_bytes);
+ }
+ return res;
+ }
+};
+
const htest = @import("test.zig");
test "sha3-224 single" {
@@ -397,3 +741,88 @@ test "SHA-3 with streaming" {
h.final(&out);
try htest.assertEqual("5780048dfa381a1d01c747906e4a08711dd34fd712ecd7c6801dd2b38fd81a89", &out);
}
+
+test "cSHAKE-128 with no context nor function name" {
+ var out: [32]u8 = undefined;
+ CShake128.hash("hello123", &out, .{});
+ try htest.assertEqual("1b85861510bc4d8e467d6f8a92270533cbaa7ba5e06c2d2a502854bac468b8b9", &out);
+}
+
+test "cSHAKE-128 with context" {
+ var out: [32]u8 = undefined;
+ CShake128.hash("hello123", &out, .{ .context = "custom" });
+ try htest.assertEqual("7509fa13a6bd3e38ad5c6fac042142c233996e40ebffc86c276f108b3b19cc6a", &out);
+}
+
+test "cSHAKE-128 with context and function" {
+ var out: [32]u8 = undefined;
+ CShake(128, "function").hash("hello123", &out, .{ .context = "custom" });
+ try htest.assertEqual("ad7f4d7db2d96587fcd5047c65d37c368f5366e3afac60bb9b66b0bb95dfb675", &out);
+}
+
+test "cSHAKE-256" {
+ var out: [32]u8 = undefined;
+ CShake256.hash("hello123", &out, .{ .context = "custom" });
+ try htest.assertEqual("dabe027eb1a6cbe3a0542d0560eb4e6b39146dd72ae1bf89c970a61bd93b1813", &out);
+}
+
+test "KMAC-128 with empty key and message" {
+ var out: [KMac128.mac_length]u8 = undefined;
+ const key = "";
+ KMac128.create(&out, "", key);
+ try htest.assertEqual("5c135c615152fb4d9784dd1155f9b6034e013fd77165c327dfa4d36701983ef7", &out);
+}
+
+test "KMAC-128" {
+ var out: [KMac128.mac_length]u8 = undefined;
+ const key = "A KMAC secret key";
+ KMac128.create(&out, "hello123", key);
+ try htest.assertEqual("1fa1c0d761129a83f9a4299ca137674de8373a3cc437799ae4c129e651627f8e", &out);
+}
+
+test "KMAC-128 with a customization string" {
+ var out: [KMac128.mac_length]u8 = undefined;
+ const key = "A KMAC secret key";
+ KMac128.createWithOptions(&out, "hello123", key, .{ .context = "custom" });
+ try htest.assertEqual("c58c6d42dc00a27dfa8e7e08f8c9307cecb5d662ddb11b6c36057fc2e0e068ba", &out);
+}
+
+test "KMACXOF-128" {
+ const key = "A KMAC secret key";
+ var xof = KMac128.init(key);
+ xof.update("hello123");
+ var out: [50]u8 = undefined;
+ xof.squeeze(&out);
+ try htest.assertEqual("628c2fb870d294b3673ac82d9f0d651aae6a5bb8084ea8cd8343cb888d075b9053173200a71f301141069c3c0322527981f7", &out);
+ xof.squeeze(&out);
+ try htest.assertEqual("7b638e178cfdac5727a4ea7694efaa967a65a1d0034501855acff506b4158d187d5a18d668e67b43f2abf61144b20ed4c09f", &out);
+}
+
+test "KMACXOF-256" {
+ const key = "A KMAC secret key";
+ var xof = KMac256.init(key);
+ xof.update("hello123");
+ var out: [50]u8 = undefined;
+ xof.squeeze(&out);
+ try htest.assertEqual("23fc644bc2655ba6fde7b7c11f2804f22e8d8c6bd7db856268bf3370ce2362703f6c7e91916a1b8c116e60edfbcb25613054", &out);
+ xof.squeeze(&out);
+ try htest.assertEqual("ff97251020ff255ee65a1c1f5f78ebe904f61211c39f973f82fbce2b196b9f51c2cb12afe51549a0f1eaf7954e657ba11af3", &out);
+}
+
+test "TupleHash-128" {
+ var st = TupleHash128.init();
+ st.update("hello");
+ st.update("123");
+ var out: [32]u8 = undefined;
+ st.final(&out);
+ try htest.assertEqual("3938d49ade8ec0f0c305ac63497b2d2e8b2f650714f9667cc41816b1c11ffd20", &out);
+}
+
+test "TupleHash-256" {
+ var st = TupleHash256.init();
+ st.update("hello");
+ st.update("123");
+ var out: [64]u8 = undefined;
+ st.final(&out);
+ try htest.assertEqual("2dca563c2882f2ba4f46a441a4c5e13fb97150d1436fe99c7e4e43a2d20d0f1cd3d38483bde4a966930606dfa6c61c4ca6400aeedfb474d1bf0d7f6a70968289", &out);
+}
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index d1d6201b80..eaa5ca9ff7 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -406,7 +406,7 @@ pub fn assert(ok: bool) void {
pub fn panic(comptime format: []const u8, args: anytype) noreturn {
@setCold(true);
- panicExtra(null, null, format, args);
+ panicExtra(@errorReturnTrace(), @returnAddress(), format, args);
}
/// `panicExtra` is useful when you want to print out an `@errorReturnTrace`
@@ -661,7 +661,7 @@ pub const StackIterator = struct {
fn isValidMemory(address: usize) bool {
// We are unable to determine validity of memory for freestanding targets
- if (native_os == .freestanding) return true;
+ if (native_os == .freestanding or native_os == .uefi) return true;
const aligned_address = address & ~@as(usize, @intCast((mem.page_size - 1)));
if (aligned_address == 0) return false;
diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig
index 74d91239f8..b6222f942f 100644
--- a/lib/std/fs/Dir.zig
+++ b/lib/std/fs/Dir.zig
@@ -220,71 +220,83 @@ pub const Iterator = switch (native_os) {
},
.haiku => struct {
dir: Dir,
- buf: [1024]u8, // TODO align(@alignOf(posix.dirent64)),
+ buf: [@sizeOf(DirEnt) + posix.PATH_MAX]u8 align(@alignOf(DirEnt)),
+ offset: usize,
index: usize,
end_index: usize,
first_iter: bool,
const Self = @This();
+ const DirEnt = posix.system.DirEnt;
pub const Error = IteratorError;
/// Memory such as file names referenced in this returned entry becomes invalid
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
pub fn next(self: *Self) Error!?Entry {
- start_over: while (true) {
- // TODO: find a better max
- const HAIKU_MAX_COUNT = 10000;
+ while (true) {
if (self.index >= self.end_index) {
if (self.first_iter) {
- posix.lseek_SET(self.dir.fd, 0) catch unreachable; // EBADF here likely means that the Dir was not opened with iteration permissions
+ switch (@as(posix.E, @enumFromInt(posix.system._kern_rewind_dir(self.dir.fd)))) {
+ .SUCCESS => {},
+ .BADF => unreachable, // Dir is invalid
+ .FAULT => unreachable,
+ .NOTDIR => unreachable,
+ .INVAL => unreachable,
+ .ACCES => return error.AccessDenied,
+ .PERM => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
self.first_iter = false;
}
const rc = posix.system._kern_read_dir(
self.dir.fd,
&self.buf,
self.buf.len,
- HAIKU_MAX_COUNT,
+ self.buf.len / @sizeOf(DirEnt),
);
if (rc == 0) return null;
if (rc < 0) {
- switch (posix.errno(rc)) {
- .BADF => unreachable, // Dir is invalid or was opened without iteration ability
+ switch (@as(posix.E, @enumFromInt(rc))) {
+ .BADF => unreachable, // Dir is invalid
.FAULT => unreachable,
.NOTDIR => unreachable,
.INVAL => unreachable,
+ .OVERFLOW => unreachable,
+ .ACCES => return error.AccessDenied,
+ .PERM => return error.AccessDenied,
else => |err| return posix.unexpectedErrno(err),
}
}
+ self.offset = 0;
self.index = 0;
- self.end_index = @as(usize, @intCast(rc));
- }
- const haiku_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
- const next_index = self.index + haiku_entry.reclen;
- self.index = next_index;
- const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&haiku_entry.name)), 0);
-
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (haiku_entry.ino == 0)) {
- continue :start_over;
+ self.end_index = @intCast(rc);
}
+ const dirent: *DirEnt = @ptrCast(@alignCast(&self.buf[self.offset]));
+ self.offset += dirent.reclen;
+ self.index += 1;
+ const name = mem.span(dirent.getName());
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or dirent.ino == 0) continue;
var stat_info: posix.Stat = undefined;
- const rc = posix.system._kern_read_stat(
+ switch (@as(posix.E, @enumFromInt(posix.system._kern_read_stat(
self.dir.fd,
- &haiku_entry.name,
+ name,
false,
&stat_info,
0,
- );
- if (rc != 0) {
- switch (posix.errno(rc)) {
- .SUCCESS => {},
- .BADF => unreachable, // Dir is invalid or was opened without iteration ability
- .FAULT => unreachable,
- .NOTDIR => unreachable,
- .INVAL => unreachable,
- else => |err| return posix.unexpectedErrno(err),
- }
+ )))) {
+ .SUCCESS => {},
+ .INVAL => unreachable,
+ .BADF => unreachable, // Dir is invalid
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .PERM => return error.AccessDenied,
+ .FAULT => unreachable,
+ .NAMETOOLONG => unreachable,
+ .LOOP => unreachable,
+ .NOENT => continue,
+ else => |err| return posix.unexpectedErrno(err),
}
const statmode = stat_info.mode & posix.S.IFMT;
@@ -315,7 +327,7 @@ pub const Iterator = switch (native_os) {
dir: Dir,
// The if guard is solely there to prevent compile errors from missing `linux.dirent64`
// definition when compiling for other OSes. It doesn't do anything when compiling for Linux.
- buf: [1024]u8 align(if (native_os != .linux) 1 else @alignOf(linux.dirent64)),
+ buf: [1024]u8 align(@alignOf(linux.dirent64)),
index: usize,
end_index: usize,
first_iter: bool,
@@ -599,8 +611,16 @@ fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
.buf = undefined,
.first_iter = first_iter_start_value,
},
- .linux, .haiku => return Iterator{
+ .linux => return Iterator{
+ .dir = self,
+ .index = 0,
+ .end_index = 0,
+ .buf = undefined,
+ .first_iter = first_iter_start_value,
+ },
+ .haiku => return Iterator{
.dir = self,
+ .offset = 0,
.index = 0,
.end_index = 0,
.buf = undefined,
@@ -626,16 +646,17 @@ fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
}
pub const Walker = struct {
- stack: std.ArrayList(StackItem),
- name_buffer: std.ArrayList(u8),
+ stack: std.ArrayListUnmanaged(StackItem),
+ name_buffer: std.ArrayListUnmanaged(u8),
+ allocator: Allocator,
- pub const WalkerEntry = struct {
+ pub const Entry = struct {
/// The containing directory. This can be used to operate directly on `basename`
/// rather than `path`, avoiding `error.NameTooLong` for deeply nested paths.
/// The directory remains open until `next` or `deinit` is called.
dir: Dir,
- basename: []const u8,
- path: []const u8,
+ basename: [:0]const u8,
+ path: [:0]const u8,
kind: Dir.Entry.Kind,
};
@@ -647,7 +668,8 @@ pub const Walker = struct {
/// After each call to this function, and on deinit(), the memory returned
/// from this function becomes invalid. A copy must be made in order to keep
/// a reference to the path.
- pub fn next(self: *Walker) !?WalkerEntry {
+ pub fn next(self: *Walker) !?Walker.Entry {
+ const gpa = self.allocator;
while (self.stack.items.len != 0) {
// `top` and `containing` become invalid after appending to `self.stack`
var top = &self.stack.items[self.stack.items.len - 1];
@@ -666,10 +688,12 @@ pub const Walker = struct {
}) |base| {
self.name_buffer.shrinkRetainingCapacity(dirname_len);
if (self.name_buffer.items.len != 0) {
- try self.name_buffer.append(fs.path.sep);
+ try self.name_buffer.append(gpa, fs.path.sep);
dirname_len += 1;
}
- try self.name_buffer.appendSlice(base.name);
+ try self.name_buffer.ensureUnusedCapacity(gpa, base.name.len + 1);
+ self.name_buffer.appendSliceAssumeCapacity(base.name);
+ self.name_buffer.appendAssumeCapacity(0);
if (base.kind == .directory) {
var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
error.NameTooLong => unreachable, // no path sep in base.name
@@ -677,18 +701,18 @@ pub const Walker = struct {
};
{
errdefer new_dir.close();
- try self.stack.append(StackItem{
+ try self.stack.append(gpa, .{
.iter = new_dir.iterateAssumeFirstIteration(),
- .dirname_len = self.name_buffer.items.len,
+ .dirname_len = self.name_buffer.items.len - 1,
});
top = &self.stack.items[self.stack.items.len - 1];
containing = &self.stack.items[self.stack.items.len - 2];
}
}
- return WalkerEntry{
+ return .{
.dir = containing.iter.dir,
- .basename = self.name_buffer.items[dirname_len..],
- .path = self.name_buffer.items,
+ .basename = self.name_buffer.items[dirname_len .. self.name_buffer.items.len - 1 :0],
+ .path = self.name_buffer.items[0 .. self.name_buffer.items.len - 1 :0],
.kind = base.kind,
};
} else {
@@ -702,37 +726,39 @@ pub const Walker = struct {
}
pub fn deinit(self: *Walker) void {
+ const gpa = self.allocator;
// Close any remaining directories except the initial one (which is always at index 0)
if (self.stack.items.len > 1) {
for (self.stack.items[1..]) |*item| {
item.iter.dir.close();
}
}
- self.stack.deinit();
- self.name_buffer.deinit();
+ self.stack.deinit(gpa);
+ self.name_buffer.deinit(gpa);
}
};
/// Recursively iterates over a directory.
+///
/// `self` must have been opened with `OpenDirOptions{.iterate = true}`.
-/// Must call `Walker.deinit` when done.
+///
+/// `Walker.deinit` releases allocated memory and directory handles.
+///
/// The order of returned file system entries is undefined.
+///
/// `self` will not be closed after walking it.
-pub fn walk(self: Dir, allocator: Allocator) !Walker {
- var name_buffer = std.ArrayList(u8).init(allocator);
- errdefer name_buffer.deinit();
-
- var stack = std.ArrayList(Walker.StackItem).init(allocator);
- errdefer stack.deinit();
+pub fn walk(self: Dir, allocator: Allocator) Allocator.Error!Walker {
+ var stack: std.ArrayListUnmanaged(Walker.StackItem) = .{};
- try stack.append(Walker.StackItem{
+ try stack.append(allocator, .{
.iter = self.iterate(),
.dirname_len = 0,
});
- return Walker{
+ return .{
.stack = stack,
- .name_buffer = name_buffer,
+ .name_buffer = .{},
+ .allocator = allocator,
};
}
@@ -1429,6 +1455,27 @@ pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) Open
.wasi => {
return openDir(self, mem.sliceTo(sub_path_c, 0), args);
},
+ .haiku => {
+ const rc = posix.system._kern_open_dir(self.fd, sub_path_c);
+ if (rc >= 0) return .{ .fd = rc };
+ switch (@as(posix.E, @enumFromInt(rc))) {
+ .FAULT => unreachable,
+ .INVAL => unreachable,
+ .BADF => unreachable,
+ .ACCES => return error.AccessDenied,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.AccessDenied,
+ .BUSY => return error.DeviceBusy,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
else => {
var symlink_flags: posix.O = .{
.ACCMODE = .RDONLY,
diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig
index 0ac4de761e..732c03e721 100644
--- a/lib/std/hash/crc.zig
+++ b/lib/std/hash/crc.zig
@@ -1,285 +1,911 @@
-// There are two implementations of CRC32 implemented with the following key characteristics:
-//
-// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
-//
-// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
-// still moderately fast just slow relative to the slicing approach.
-
-const std = @import("std");
-const builtin = @import("builtin");
-const debug = std.debug;
-const testing = std.testing;
-
-pub usingnamespace @import("crc/catalog.zig");
-
-pub fn Algorithm(comptime W: type) type {
- return struct {
- polynomial: W,
- initial: W,
- reflect_input: bool,
- reflect_output: bool,
- xor_output: W,
- };
-}
+//! This file is auto-generated by tools/update_crc_catalog.zig.
-pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type {
- return struct {
- const Self = @This();
- const I = if (@bitSizeOf(W) < 8) u8 else W;
- const lookup_table = blk: {
- @setEvalBranchQuota(2500);
-
- const poly = if (algorithm.reflect_input)
- @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
- else
- @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
-
- var table: [256]I = undefined;
- for (&table, 0..) |*e, i| {
- var crc: I = i;
- if (algorithm.reflect_input) {
- var j: usize = 0;
- while (j < 8) : (j += 1) {
- crc = (crc >> 1) ^ ((crc & 1) * poly);
- }
- } else {
- crc <<= @bitSizeOf(I) - 8;
- var j: usize = 0;
- while (j < 8) : (j += 1) {
- crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
- }
- }
- e.* = crc;
- }
- break :blk table;
- };
-
- crc: I,
-
- pub fn init() Self {
- const initial = if (algorithm.reflect_input)
- @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
- else
- @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
- return Self{ .crc = initial };
- }
-
- inline fn tableEntry(index: I) I {
- return lookup_table[@as(u8, @intCast(index & 0xFF))];
- }
-
- pub fn update(self: *Self, bytes: []const u8) void {
- var i: usize = 0;
- if (@bitSizeOf(I) <= 8) {
- while (i < bytes.len) : (i += 1) {
- self.crc = tableEntry(self.crc ^ bytes[i]);
- }
- } else if (algorithm.reflect_input) {
- while (i < bytes.len) : (i += 1) {
- const table_index = self.crc ^ bytes[i];
- self.crc = tableEntry(table_index) ^ (self.crc >> 8);
- }
- } else {
- while (i < bytes.len) : (i += 1) {
- const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i];
- self.crc = tableEntry(table_index) ^ (self.crc << 8);
- }
- }
- }
-
- pub fn final(self: Self) W {
- var c = self.crc;
- if (algorithm.reflect_input != algorithm.reflect_output) {
- c = @bitReverse(c);
- }
- if (!algorithm.reflect_output) {
- c >>= @bitSizeOf(I) - @bitSizeOf(W);
- }
- return @as(W, @intCast(c ^ algorithm.xor_output));
- }
-
- pub fn hash(bytes: []const u8) W {
- var c = Self.init();
- c.update(bytes);
- return c.final();
- }
- };
-}
+const impl = @import("crc/impl.zig");
-pub const Polynomial = enum(u32) {
- IEEE = 0xedb88320,
- Castagnoli = 0x82f63b78,
- Koopman = 0xeb31d82e,
- _,
-};
+pub const Crc = impl.Crc;
+pub const Polynomial = impl.Polynomial;
+pub const Crc32WithPoly = impl.Crc32WithPoly;
+pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly;
// IEEE is by far the most common CRC and so is aliased by default.
pub const Crc32 = Crc32WithPoly(.IEEE);
-// slicing-by-8 crc32 implementation.
-pub fn Crc32WithPoly(comptime poly: Polynomial) type {
- return struct {
- const Self = @This();
- const lookup_tables = block: {
- @setEvalBranchQuota(20000);
- var tables: [8][256]u32 = undefined;
-
- for (&tables[0], 0..) |*e, i| {
- var crc = @as(u32, @intCast(i));
- var j: usize = 0;
- while (j < 8) : (j += 1) {
- if (crc & 1 == 1) {
- crc = (crc >> 1) ^ @intFromEnum(poly);
- } else {
- crc = (crc >> 1);
- }
- }
- e.* = crc;
- }
-
- var i: usize = 0;
- while (i < 256) : (i += 1) {
- var crc = tables[0][i];
- var j: usize = 1;
- while (j < 8) : (j += 1) {
- const index: u8 = @truncate(crc);
- crc = tables[0][index] ^ (crc >> 8);
- tables[j][i] = crc;
- }
- }
-
- break :block tables;
- };
-
- crc: u32,
-
- pub fn init() Self {
- return Self{ .crc = 0xffffffff };
- }
-
- pub fn update(self: *Self, input: []const u8) void {
- var i: usize = 0;
- while (i + 8 <= input.len) : (i += 8) {
- const p = input[i..][0..8];
-
- // Unrolling this way gives ~50Mb/s increase
- self.crc ^= std.mem.readInt(u32, p[0..4], .little);
-
- self.crc =
- lookup_tables[0][p[7]] ^
- lookup_tables[1][p[6]] ^
- lookup_tables[2][p[5]] ^
- lookup_tables[3][p[4]] ^
- lookup_tables[4][@as(u8, @truncate(self.crc >> 24))] ^
- lookup_tables[5][@as(u8, @truncate(self.crc >> 16))] ^
- lookup_tables[6][@as(u8, @truncate(self.crc >> 8))] ^
- lookup_tables[7][@as(u8, @truncate(self.crc >> 0))];
- }
-
- while (i < input.len) : (i += 1) {
- const index = @as(u8, @truncate(self.crc)) ^ input[i];
- self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
- }
- }
-
- pub fn final(self: *Self) u32 {
- return ~self.crc;
- }
-
- pub fn hash(input: []const u8) u32 {
- var c = Self.init();
- c.update(input);
- return c.final();
- }
- };
-}
-
-const verify = @import("verify.zig");
-
-test "crc32 ieee" {
- const Crc32Ieee = Crc32WithPoly(.IEEE);
-
- try testing.expect(Crc32Ieee.hash("") == 0x00000000);
- try testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
- try testing.expect(Crc32Ieee.hash("abc") == 0x352441c2);
-}
-
-test "crc32 castagnoli" {
- const Crc32Castagnoli = Crc32WithPoly(.Castagnoli);
-
- try testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
- try testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
- try testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
-}
-
-test "crc32 iterative" {
- try verify.iterativeApi(Crc32WithPoly(.IEEE));
-}
-
-// half-byte lookup table implementation.
-pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
- return struct {
- const Self = @This();
- const lookup_table = block: {
- var table: [16]u32 = undefined;
-
- for (&table, 0..) |*e, i| {
- var crc = @as(u32, @intCast(i * 16));
- var j: usize = 0;
- while (j < 8) : (j += 1) {
- if (crc & 1 == 1) {
- crc = (crc >> 1) ^ @intFromEnum(poly);
- } else {
- crc = (crc >> 1);
- }
- }
- e.* = crc;
- }
-
- break :block table;
- };
-
- crc: u32,
-
- pub fn init() Self {
- return Self{ .crc = 0xffffffff };
- }
-
- pub fn update(self: *Self, input: []const u8) void {
- for (input) |b| {
- self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 0)))] ^ (self.crc >> 4);
- self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 4)))] ^ (self.crc >> 4);
- }
- }
-
- pub fn final(self: *Self) u32 {
- return ~self.crc;
- }
-
- pub fn hash(input: []const u8) u32 {
- var c = Self.init();
- c.update(input);
- return c.final();
- }
- };
-}
-
-test "small crc32 iterative" {
- try verify.iterativeApi(Crc32SmallWithPoly(.IEEE));
+test {
+ _ = @import("crc/test.zig");
}
-test "small crc32 ieee" {
- const Crc32Ieee = Crc32SmallWithPoly(.IEEE);
-
- try testing.expect(Crc32Ieee.hash("") == 0x00000000);
- try testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
- try testing.expect(Crc32Ieee.hash("abc") == 0x352441c2);
-}
-
-test "small crc32 castagnoli" {
- const Crc32Castagnoli = Crc32SmallWithPoly(.Castagnoli);
-
- try testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
- try testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
- try testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
-}
+pub const Crc3Gsm = Crc(u3, .{
+ .polynomial = 0x3,
+ .initial = 0x0,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x7,
+});
+
+pub const Crc3Rohc = Crc(u3, .{
+ .polynomial = 0x3,
+ .initial = 0x7,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0,
+});
+
+pub const Crc4G704 = Crc(u4, .{
+ .polynomial = 0x3,
+ .initial = 0x0,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0,
+});
+
+pub const Crc4Interlaken = Crc(u4, .{
+ .polynomial = 0x3,
+ .initial = 0xf,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xf,
+});
+
+pub const Crc5EpcC1g2 = Crc(u5, .{
+ .polynomial = 0x09,
+ .initial = 0x09,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc5G704 = Crc(u5, .{
+ .polynomial = 0x15,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc5Usb = Crc(u5, .{
+ .polynomial = 0x05,
+ .initial = 0x1f,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x1f,
+});
+
+pub const Crc6Cdma2000A = Crc(u6, .{
+ .polynomial = 0x27,
+ .initial = 0x3f,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc6Cdma2000B = Crc(u6, .{
+ .polynomial = 0x07,
+ .initial = 0x3f,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc6Darc = Crc(u6, .{
+ .polynomial = 0x19,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc6G704 = Crc(u6, .{
+ .polynomial = 0x03,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc6Gsm = Crc(u6, .{
+ .polynomial = 0x2f,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x3f,
+});
+
+pub const Crc7Mmc = Crc(u7, .{
+ .polynomial = 0x09,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc7Rohc = Crc(u7, .{
+ .polynomial = 0x4f,
+ .initial = 0x7f,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc7Umts = Crc(u7, .{
+ .polynomial = 0x45,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Autosar = Crc(u8, .{
+ .polynomial = 0x2f,
+ .initial = 0xff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xff,
+});
+
+pub const Crc8Bluetooth = Crc(u8, .{
+ .polynomial = 0xa7,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Cdma2000 = Crc(u8, .{
+ .polynomial = 0x9b,
+ .initial = 0xff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Darc = Crc(u8, .{
+ .polynomial = 0x39,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc8DvbS2 = Crc(u8, .{
+ .polynomial = 0xd5,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8GsmA = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8GsmB = Crc(u8, .{
+ .polynomial = 0x49,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xff,
+});
+
+pub const Crc8Hitag = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0xff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8I4321 = Crc(u8, .{
+ .polynomial = 0x07,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x55,
+});
+
+pub const Crc8ICode = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0xfd,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Lte = Crc(u8, .{
+ .polynomial = 0x9b,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8MaximDow = Crc(u8, .{
+ .polynomial = 0x31,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc8MifareMad = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0xc7,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Nrsc5 = Crc(u8, .{
+ .polynomial = 0x31,
+ .initial = 0xff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Opensafety = Crc(u8, .{
+ .polynomial = 0x2f,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Rohc = Crc(u8, .{
+ .polynomial = 0x07,
+ .initial = 0xff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc8SaeJ1850 = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0xff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xff,
+});
+
+pub const Crc8Smbus = Crc(u8, .{
+ .polynomial = 0x07,
+ .initial = 0x00,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Tech3250 = Crc(u8, .{
+ .polynomial = 0x1d,
+ .initial = 0xff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc8Wcdma = Crc(u8, .{
+ .polynomial = 0x9b,
+ .initial = 0x00,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00,
+});
+
+pub const Crc10Atm = Crc(u10, .{
+ .polynomial = 0x233,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc10Cdma2000 = Crc(u10, .{
+ .polynomial = 0x3d9,
+ .initial = 0x3ff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc10Gsm = Crc(u10, .{
+ .polynomial = 0x175,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x3ff,
+});
+
+pub const Crc11Flexray = Crc(u11, .{
+ .polynomial = 0x385,
+ .initial = 0x01a,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc11Umts = Crc(u11, .{
+ .polynomial = 0x307,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc12Cdma2000 = Crc(u12, .{
+ .polynomial = 0xf13,
+ .initial = 0xfff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc12Dect = Crc(u12, .{
+ .polynomial = 0x80f,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000,
+});
+
+pub const Crc12Gsm = Crc(u12, .{
+ .polynomial = 0xd31,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xfff,
+});
+
+pub const Crc12Umts = Crc(u12, .{
+ .polynomial = 0x80f,
+ .initial = 0x000,
+ .reflect_input = false,
+ .reflect_output = true,
+ .xor_output = 0x000,
+});
+
+pub const Crc13Bbc = Crc(u13, .{
+ .polynomial = 0x1cf5,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc14Darc = Crc(u14, .{
+ .polynomial = 0x0805,
+ .initial = 0x0000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc14Gsm = Crc(u14, .{
+ .polynomial = 0x202d,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x3fff,
+});
+
+pub const Crc15Can = Crc(u15, .{
+ .polynomial = 0x4599,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc15Mpt1327 = Crc(u15, .{
+ .polynomial = 0x6815,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0001,
+});
+
+pub const Crc16Arc = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0x0000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Cdma2000 = Crc(u16, .{
+ .polynomial = 0xc867,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Cms = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Dds110 = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0x800d,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16DectR = Crc(u16, .{
+ .polynomial = 0x0589,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0001,
+});
+
+pub const Crc16DectX = Crc(u16, .{
+ .polynomial = 0x0589,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Dnp = Crc(u16, .{
+ .polynomial = 0x3d65,
+ .initial = 0x0000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16En13757 = Crc(u16, .{
+ .polynomial = 0x3d65,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Genibus = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Gsm = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Ibm3740 = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16IbmSdlc = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16IsoIec144433A = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xc6c6,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Kermit = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0x0000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Lj1200 = Crc(u16, .{
+ .polynomial = 0x6f63,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16M17 = Crc(u16, .{
+ .polynomial = 0x5935,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16MaximDow = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0x0000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Mcrf4xx = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Modbus = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0xffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Nrsc5 = Crc(u16, .{
+ .polynomial = 0x080b,
+ .initial = 0xffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16OpensafetyA = Crc(u16, .{
+ .polynomial = 0x5935,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16OpensafetyB = Crc(u16, .{
+ .polynomial = 0x755b,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Profibus = Crc(u16, .{
+ .polynomial = 0x1dcf,
+ .initial = 0xffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Riello = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0xb2aa,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16SpiFujitsu = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0x1d0f,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16T10Dif = Crc(u16, .{
+ .polynomial = 0x8bb7,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Teledisk = Crc(u16, .{
+ .polynomial = 0xa097,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Tms37157 = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0x89ec,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Umts = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc16Usb = Crc(u16, .{
+ .polynomial = 0x8005,
+ .initial = 0xffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffff,
+});
+
+pub const Crc16Xmodem = Crc(u16, .{
+ .polynomial = 0x1021,
+ .initial = 0x0000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000,
+});
+
+pub const Crc17CanFd = Crc(u17, .{
+ .polynomial = 0x1685b,
+ .initial = 0x00000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00000,
+});
+
+pub const Crc21CanFd = Crc(u21, .{
+ .polynomial = 0x102899,
+ .initial = 0x000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24Ble = Crc(u24, .{
+ .polynomial = 0x00065b,
+ .initial = 0x555555,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24FlexrayA = Crc(u24, .{
+ .polynomial = 0x5d6dcb,
+ .initial = 0xfedcba,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24FlexrayB = Crc(u24, .{
+ .polynomial = 0x5d6dcb,
+ .initial = 0xabcdef,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24Interlaken = Crc(u24, .{
+ .polynomial = 0x328b63,
+ .initial = 0xffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffff,
+});
+
+pub const Crc24LteA = Crc(u24, .{
+ .polynomial = 0x864cfb,
+ .initial = 0x000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24LteB = Crc(u24, .{
+ .polynomial = 0x800063,
+ .initial = 0x000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24Openpgp = Crc(u24, .{
+ .polynomial = 0x864cfb,
+ .initial = 0xb704ce,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x000000,
+});
+
+pub const Crc24Os9 = Crc(u24, .{
+ .polynomial = 0x800063,
+ .initial = 0xffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffff,
+});
+
+pub const Crc30Cdma = Crc(u30, .{
+ .polynomial = 0x2030b9c7,
+ .initial = 0x3fffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x3fffffff,
+});
+
+pub const Crc31Philips = Crc(u31, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0x7fffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x7fffffff,
+});
+
+pub const Crc32Aixm = Crc(u32, .{
+ .polynomial = 0x814141ab,
+ .initial = 0x00000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc32Autosar = Crc(u32, .{
+ .polynomial = 0xf4acfb13,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32Base91D = Crc(u32, .{
+ .polynomial = 0xa833982b,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32Bzip2 = Crc(u32, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0xffffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32CdRomEdc = Crc(u32, .{
+ .polynomial = 0x8001801b,
+ .initial = 0x00000000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc32Cksum = Crc(u32, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0x00000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32Iscsi = Crc(u32, .{
+ .polynomial = 0x1edc6f41,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32IsoHdlc = Crc(u32, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffff,
+});
+
+pub const Crc32Jamcrc = Crc(u32, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc32Mef = Crc(u32, .{
+ .polynomial = 0x741b8cd7,
+ .initial = 0xffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc32Mpeg2 = Crc(u32, .{
+ .polynomial = 0x04c11db7,
+ .initial = 0xffffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc32Xfer = Crc(u32, .{
+ .polynomial = 0x000000af,
+ .initial = 0x00000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x00000000,
+});
+
+pub const Crc40Gsm = Crc(u40, .{
+ .polynomial = 0x0004820009,
+ .initial = 0x0000000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffffffff,
+});
+
+pub const Crc64Ecma182 = Crc(u64, .{
+ .polynomial = 0x42f0e1eba9ea3693,
+ .initial = 0x0000000000000000,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0x0000000000000000,
+});
+
+pub const Crc64GoIso = Crc(u64, .{
+ .polynomial = 0x000000000000001b,
+ .initial = 0xffffffffffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffffffffffff,
+});
+
+pub const Crc64Ms = Crc(u64, .{
+ .polynomial = 0x259c84cba6426349,
+ .initial = 0xffffffffffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000000000000000,
+});
+
+pub const Crc64Redis = Crc(u64, .{
+ .polynomial = 0xad93d23594c935a9,
+ .initial = 0x0000000000000000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x0000000000000000,
+});
+
+pub const Crc64We = Crc(u64, .{
+ .polynomial = 0x42f0e1eba9ea3693,
+ .initial = 0xffffffffffffffff,
+ .reflect_input = false,
+ .reflect_output = false,
+ .xor_output = 0xffffffffffffffff,
+});
+
+pub const Crc64Xz = Crc(u64, .{
+ .polynomial = 0x42f0e1eba9ea3693,
+ .initial = 0xffffffffffffffff,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0xffffffffffffffff,
+});
+
+pub const Crc82Darc = Crc(u82, .{
+ .polynomial = 0x0308c0111011401440411,
+ .initial = 0x000000000000000000000,
+ .reflect_input = true,
+ .reflect_output = true,
+ .xor_output = 0x000000000000000000000,
+});
diff --git a/lib/std/hash/crc/catalog.zig b/lib/std/hash/crc/catalog.zig
deleted file mode 100644
index ed08accce6..0000000000
--- a/lib/std/hash/crc/catalog.zig
+++ /dev/null
@@ -1,903 +0,0 @@
-//! This file is auto-generated by tools/update_crc_catalog.zig.
-
-const Crc = @import("../crc.zig").Crc;
-
-test {
- _ = @import("catalog_test.zig");
-}
-
-pub const Crc3Gsm = Crc(u3, .{
- .polynomial = 0x3,
- .initial = 0x0,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x7,
-});
-
-pub const Crc3Rohc = Crc(u3, .{
- .polynomial = 0x3,
- .initial = 0x7,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0,
-});
-
-pub const Crc4G704 = Crc(u4, .{
- .polynomial = 0x3,
- .initial = 0x0,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0,
-});
-
-pub const Crc4Interlaken = Crc(u4, .{
- .polynomial = 0x3,
- .initial = 0xf,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xf,
-});
-
-pub const Crc5EpcC1g2 = Crc(u5, .{
- .polynomial = 0x09,
- .initial = 0x09,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc5G704 = Crc(u5, .{
- .polynomial = 0x15,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc5Usb = Crc(u5, .{
- .polynomial = 0x05,
- .initial = 0x1f,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x1f,
-});
-
-pub const Crc6Cdma2000A = Crc(u6, .{
- .polynomial = 0x27,
- .initial = 0x3f,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc6Cdma2000B = Crc(u6, .{
- .polynomial = 0x07,
- .initial = 0x3f,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc6Darc = Crc(u6, .{
- .polynomial = 0x19,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc6G704 = Crc(u6, .{
- .polynomial = 0x03,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc6Gsm = Crc(u6, .{
- .polynomial = 0x2f,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x3f,
-});
-
-pub const Crc7Mmc = Crc(u7, .{
- .polynomial = 0x09,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc7Rohc = Crc(u7, .{
- .polynomial = 0x4f,
- .initial = 0x7f,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc7Umts = Crc(u7, .{
- .polynomial = 0x45,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Autosar = Crc(u8, .{
- .polynomial = 0x2f,
- .initial = 0xff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xff,
-});
-
-pub const Crc8Bluetooth = Crc(u8, .{
- .polynomial = 0xa7,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc8Cdma2000 = Crc(u8, .{
- .polynomial = 0x9b,
- .initial = 0xff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Darc = Crc(u8, .{
- .polynomial = 0x39,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc8DvbS2 = Crc(u8, .{
- .polynomial = 0xd5,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8GsmA = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8GsmB = Crc(u8, .{
- .polynomial = 0x49,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xff,
-});
-
-pub const Crc8Hitag = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0xff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8I4321 = Crc(u8, .{
- .polynomial = 0x07,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x55,
-});
-
-pub const Crc8ICode = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0xfd,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Lte = Crc(u8, .{
- .polynomial = 0x9b,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8MaximDow = Crc(u8, .{
- .polynomial = 0x31,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc8MifareMad = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0xc7,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Nrsc5 = Crc(u8, .{
- .polynomial = 0x31,
- .initial = 0xff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Opensafety = Crc(u8, .{
- .polynomial = 0x2f,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Rohc = Crc(u8, .{
- .polynomial = 0x07,
- .initial = 0xff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc8SaeJ1850 = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0xff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xff,
-});
-
-pub const Crc8Smbus = Crc(u8, .{
- .polynomial = 0x07,
- .initial = 0x00,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00,
-});
-
-pub const Crc8Tech3250 = Crc(u8, .{
- .polynomial = 0x1d,
- .initial = 0xff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc8Wcdma = Crc(u8, .{
- .polynomial = 0x9b,
- .initial = 0x00,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00,
-});
-
-pub const Crc10Atm = Crc(u10, .{
- .polynomial = 0x233,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc10Cdma2000 = Crc(u10, .{
- .polynomial = 0x3d9,
- .initial = 0x3ff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc10Gsm = Crc(u10, .{
- .polynomial = 0x175,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x3ff,
-});
-
-pub const Crc11Flexray = Crc(u11, .{
- .polynomial = 0x385,
- .initial = 0x01a,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc11Umts = Crc(u11, .{
- .polynomial = 0x307,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc12Cdma2000 = Crc(u12, .{
- .polynomial = 0xf13,
- .initial = 0xfff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc12Dect = Crc(u12, .{
- .polynomial = 0x80f,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000,
-});
-
-pub const Crc12Gsm = Crc(u12, .{
- .polynomial = 0xd31,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xfff,
-});
-
-pub const Crc12Umts = Crc(u12, .{
- .polynomial = 0x80f,
- .initial = 0x000,
- .reflect_input = false,
- .reflect_output = true,
- .xor_output = 0x000,
-});
-
-pub const Crc13Bbc = Crc(u13, .{
- .polynomial = 0x1cf5,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc14Darc = Crc(u14, .{
- .polynomial = 0x0805,
- .initial = 0x0000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc14Gsm = Crc(u14, .{
- .polynomial = 0x202d,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x3fff,
-});
-
-pub const Crc15Can = Crc(u15, .{
- .polynomial = 0x4599,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc15Mpt1327 = Crc(u15, .{
- .polynomial = 0x6815,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0001,
-});
-
-pub const Crc16Arc = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0x0000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Cdma2000 = Crc(u16, .{
- .polynomial = 0xc867,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Cms = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Dds110 = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0x800d,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16DectR = Crc(u16, .{
- .polynomial = 0x0589,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0001,
-});
-
-pub const Crc16DectX = Crc(u16, .{
- .polynomial = 0x0589,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Dnp = Crc(u16, .{
- .polynomial = 0x3d65,
- .initial = 0x0000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffff,
-});
-
-pub const Crc16En13757 = Crc(u16, .{
- .polynomial = 0x3d65,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Genibus = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Gsm = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Ibm3740 = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16IbmSdlc = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffff,
-});
-
-pub const Crc16IsoIec144433A = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xc6c6,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Kermit = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0x0000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Lj1200 = Crc(u16, .{
- .polynomial = 0x6f63,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16M17 = Crc(u16, .{
- .polynomial = 0x5935,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16MaximDow = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0x0000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Mcrf4xx = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Modbus = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0xffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Nrsc5 = Crc(u16, .{
- .polynomial = 0x080b,
- .initial = 0xffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16OpensafetyA = Crc(u16, .{
- .polynomial = 0x5935,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16OpensafetyB = Crc(u16, .{
- .polynomial = 0x755b,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Profibus = Crc(u16, .{
- .polynomial = 0x1dcf,
- .initial = 0xffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Riello = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0xb2aa,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16SpiFujitsu = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0x1d0f,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16T10Dif = Crc(u16, .{
- .polynomial = 0x8bb7,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Teledisk = Crc(u16, .{
- .polynomial = 0xa097,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Tms37157 = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0x89ec,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Umts = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc16Usb = Crc(u16, .{
- .polynomial = 0x8005,
- .initial = 0xffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffff,
-});
-
-pub const Crc16Xmodem = Crc(u16, .{
- .polynomial = 0x1021,
- .initial = 0x0000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000,
-});
-
-pub const Crc17CanFd = Crc(u17, .{
- .polynomial = 0x1685b,
- .initial = 0x00000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00000,
-});
-
-pub const Crc21CanFd = Crc(u21, .{
- .polynomial = 0x102899,
- .initial = 0x000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24Ble = Crc(u24, .{
- .polynomial = 0x00065b,
- .initial = 0x555555,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x000000,
-});
-
-pub const Crc24FlexrayA = Crc(u24, .{
- .polynomial = 0x5d6dcb,
- .initial = 0xfedcba,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24FlexrayB = Crc(u24, .{
- .polynomial = 0x5d6dcb,
- .initial = 0xabcdef,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24Interlaken = Crc(u24, .{
- .polynomial = 0x328b63,
- .initial = 0xffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffff,
-});
-
-pub const Crc24LteA = Crc(u24, .{
- .polynomial = 0x864cfb,
- .initial = 0x000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24LteB = Crc(u24, .{
- .polynomial = 0x800063,
- .initial = 0x000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24Openpgp = Crc(u24, .{
- .polynomial = 0x864cfb,
- .initial = 0xb704ce,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x000000,
-});
-
-pub const Crc24Os9 = Crc(u24, .{
- .polynomial = 0x800063,
- .initial = 0xffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffff,
-});
-
-pub const Crc30Cdma = Crc(u30, .{
- .polynomial = 0x2030b9c7,
- .initial = 0x3fffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x3fffffff,
-});
-
-pub const Crc31Philips = Crc(u31, .{
- .polynomial = 0x04c11db7,
- .initial = 0x7fffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x7fffffff,
-});
-
-pub const Crc32Aixm = Crc(u32, .{
- .polynomial = 0x814141ab,
- .initial = 0x00000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00000000,
-});
-
-pub const Crc32Autosar = Crc(u32, .{
- .polynomial = 0xf4acfb13,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32Base91D = Crc(u32, .{
- .polynomial = 0xa833982b,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32Bzip2 = Crc(u32, .{
- .polynomial = 0x04c11db7,
- .initial = 0xffffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32CdRomEdc = Crc(u32, .{
- .polynomial = 0x8001801b,
- .initial = 0x00000000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00000000,
-});
-
-pub const Crc32Cksum = Crc(u32, .{
- .polynomial = 0x04c11db7,
- .initial = 0x00000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32Iscsi = Crc(u32, .{
- .polynomial = 0x1edc6f41,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32IsoHdlc = Crc(u32, .{
- .polynomial = 0x04c11db7,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffff,
-});
-
-pub const Crc32Jamcrc = Crc(u32, .{
- .polynomial = 0x04c11db7,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00000000,
-});
-
-pub const Crc32Mef = Crc(u32, .{
- .polynomial = 0x741b8cd7,
- .initial = 0xffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x00000000,
-});
-
-pub const Crc32Mpeg2 = Crc(u32, .{
- .polynomial = 0x04c11db7,
- .initial = 0xffffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00000000,
-});
-
-pub const Crc32Xfer = Crc(u32, .{
- .polynomial = 0x000000af,
- .initial = 0x00000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x00000000,
-});
-
-pub const Crc40Gsm = Crc(u40, .{
- .polynomial = 0x0004820009,
- .initial = 0x0000000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffffffff,
-});
-
-pub const Crc64Ecma182 = Crc(u64, .{
- .polynomial = 0x42f0e1eba9ea3693,
- .initial = 0x0000000000000000,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0x0000000000000000,
-});
-
-pub const Crc64GoIso = Crc(u64, .{
- .polynomial = 0x000000000000001b,
- .initial = 0xffffffffffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffffffffffff,
-});
-
-pub const Crc64Ms = Crc(u64, .{
- .polynomial = 0x259c84cba6426349,
- .initial = 0xffffffffffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000000000000000,
-});
-
-pub const Crc64Redis = Crc(u64, .{
- .polynomial = 0xad93d23594c935a9,
- .initial = 0x0000000000000000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x0000000000000000,
-});
-
-pub const Crc64We = Crc(u64, .{
- .polynomial = 0x42f0e1eba9ea3693,
- .initial = 0xffffffffffffffff,
- .reflect_input = false,
- .reflect_output = false,
- .xor_output = 0xffffffffffffffff,
-});
-
-pub const Crc64Xz = Crc(u64, .{
- .polynomial = 0x42f0e1eba9ea3693,
- .initial = 0xffffffffffffffff,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0xffffffffffffffff,
-});
-
-pub const Crc82Darc = Crc(u82, .{
- .polynomial = 0x0308c0111011401440411,
- .initial = 0x000000000000000000000,
- .reflect_input = true,
- .reflect_output = true,
- .xor_output = 0x000000000000000000000,
-});
diff --git a/lib/std/hash/crc/impl.zig b/lib/std/hash/crc/impl.zig
new file mode 100644
index 0000000000..f0fd5ac14e
--- /dev/null
+++ b/lib/std/hash/crc/impl.zig
@@ -0,0 +1,241 @@
+// There is a generic CRC implementation "Crc()" which can be paramterized via
+// the Algorithm struct for a plethora of uses, along with two implementations
+// of CRC32 implemented with the following key characteristics:
+//
+// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
+//
+// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
+// still moderately fast just slow relative to the slicing approach.
+//
+// The primary interface for all of the standard CRC algorithms is the
+// generated file "crc.zig", which uses the implementation code here to define
+// many standard CRCs.
+
+const std = @import("std");
+
+pub fn Algorithm(comptime W: type) type {
+ return struct {
+ polynomial: W,
+ initial: W,
+ reflect_input: bool,
+ reflect_output: bool,
+ xor_output: W,
+ };
+}
+
+pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type {
+ return struct {
+ const Self = @This();
+ const I = if (@bitSizeOf(W) < 8) u8 else W;
+ const lookup_table = blk: {
+ @setEvalBranchQuota(2500);
+
+ const poly = if (algorithm.reflect_input)
+ @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
+ else
+ @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
+
+ var table: [256]I = undefined;
+ for (&table, 0..) |*e, i| {
+ var crc: I = i;
+ if (algorithm.reflect_input) {
+ var j: usize = 0;
+ while (j < 8) : (j += 1) {
+ crc = (crc >> 1) ^ ((crc & 1) * poly);
+ }
+ } else {
+ crc <<= @bitSizeOf(I) - 8;
+ var j: usize = 0;
+ while (j < 8) : (j += 1) {
+ crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
+ }
+ }
+ e.* = crc;
+ }
+ break :blk table;
+ };
+
+ crc: I,
+
+ pub fn init() Self {
+ const initial = if (algorithm.reflect_input)
+ @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
+ else
+ @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
+ return Self{ .crc = initial };
+ }
+
+ inline fn tableEntry(index: I) I {
+ return lookup_table[@as(u8, @intCast(index & 0xFF))];
+ }
+
+ pub fn update(self: *Self, bytes: []const u8) void {
+ var i: usize = 0;
+ if (@bitSizeOf(I) <= 8) {
+ while (i < bytes.len) : (i += 1) {
+ self.crc = tableEntry(self.crc ^ bytes[i]);
+ }
+ } else if (algorithm.reflect_input) {
+ while (i < bytes.len) : (i += 1) {
+ const table_index = self.crc ^ bytes[i];
+ self.crc = tableEntry(table_index) ^ (self.crc >> 8);
+ }
+ } else {
+ while (i < bytes.len) : (i += 1) {
+ const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i];
+ self.crc = tableEntry(table_index) ^ (self.crc << 8);
+ }
+ }
+ }
+
+ pub fn final(self: Self) W {
+ var c = self.crc;
+ if (algorithm.reflect_input != algorithm.reflect_output) {
+ c = @bitReverse(c);
+ }
+ if (!algorithm.reflect_output) {
+ c >>= @bitSizeOf(I) - @bitSizeOf(W);
+ }
+ return @as(W, @intCast(c ^ algorithm.xor_output));
+ }
+
+ pub fn hash(bytes: []const u8) W {
+ var c = Self.init();
+ c.update(bytes);
+ return c.final();
+ }
+ };
+}
+
+pub const Polynomial = enum(u32) {
+ IEEE = 0xedb88320,
+ Castagnoli = 0x82f63b78,
+ Koopman = 0xeb31d82e,
+ _,
+};
+
+// slicing-by-8 crc32 implementation.
+pub fn Crc32WithPoly(comptime poly: Polynomial) type {
+ return struct {
+ const Self = @This();
+ const lookup_tables = block: {
+ @setEvalBranchQuota(20000);
+ var tables: [8][256]u32 = undefined;
+
+ for (&tables[0], 0..) |*e, i| {
+ var crc = @as(u32, @intCast(i));
+ var j: usize = 0;
+ while (j < 8) : (j += 1) {
+ if (crc & 1 == 1) {
+ crc = (crc >> 1) ^ @intFromEnum(poly);
+ } else {
+ crc = (crc >> 1);
+ }
+ }
+ e.* = crc;
+ }
+
+ var i: usize = 0;
+ while (i < 256) : (i += 1) {
+ var crc = tables[0][i];
+ var j: usize = 1;
+ while (j < 8) : (j += 1) {
+ const index: u8 = @truncate(crc);
+ crc = tables[0][index] ^ (crc >> 8);
+ tables[j][i] = crc;
+ }
+ }
+
+ break :block tables;
+ };
+
+ crc: u32,
+
+ pub fn init() Self {
+ return Self{ .crc = 0xffffffff };
+ }
+
+ pub fn update(self: *Self, input: []const u8) void {
+ var i: usize = 0;
+ while (i + 8 <= input.len) : (i += 8) {
+ const p = input[i..][0..8];
+
+ // Unrolling this way gives ~50Mb/s increase
+ self.crc ^= std.mem.readInt(u32, p[0..4], .little);
+
+ self.crc =
+ lookup_tables[0][p[7]] ^
+ lookup_tables[1][p[6]] ^
+ lookup_tables[2][p[5]] ^
+ lookup_tables[3][p[4]] ^
+ lookup_tables[4][@as(u8, @truncate(self.crc >> 24))] ^
+ lookup_tables[5][@as(u8, @truncate(self.crc >> 16))] ^
+ lookup_tables[6][@as(u8, @truncate(self.crc >> 8))] ^
+ lookup_tables[7][@as(u8, @truncate(self.crc >> 0))];
+ }
+
+ while (i < input.len) : (i += 1) {
+ const index = @as(u8, @truncate(self.crc)) ^ input[i];
+ self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
+ }
+ }
+
+ pub fn final(self: *Self) u32 {
+ return ~self.crc;
+ }
+
+ pub fn hash(input: []const u8) u32 {
+ var c = Self.init();
+ c.update(input);
+ return c.final();
+ }
+ };
+}
+
+// half-byte lookup table implementation.
+pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
+ return struct {
+ const Self = @This();
+ const lookup_table = block: {
+ var table: [16]u32 = undefined;
+
+ for (&table, 0..) |*e, i| {
+ var crc = @as(u32, @intCast(i * 16));
+ var j: usize = 0;
+ while (j < 8) : (j += 1) {
+ if (crc & 1 == 1) {
+ crc = (crc >> 1) ^ @intFromEnum(poly);
+ } else {
+ crc = (crc >> 1);
+ }
+ }
+ e.* = crc;
+ }
+
+ break :block table;
+ };
+
+ crc: u32,
+
+ pub fn init() Self {
+ return Self{ .crc = 0xffffffff };
+ }
+
+ pub fn update(self: *Self, input: []const u8) void {
+ for (input) |b| {
+ self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 0)))] ^ (self.crc >> 4);
+ self.crc = lookup_table[@as(u4, @truncate(self.crc ^ (b >> 4)))] ^ (self.crc >> 4);
+ }
+ }
+
+ pub fn final(self: *Self) u32 {
+ return ~self.crc;
+ }
+
+ pub fn hash(input: []const u8) u32 {
+ var c = Self.init();
+ c.update(input);
+ return c.final();
+ }
+ };
+}
diff --git a/lib/std/hash/crc/catalog_test.zig b/lib/std/hash/crc/test.zig
index ab89745ca8..c9cabf6463 100644
--- a/lib/std/hash/crc/catalog_test.zig
+++ b/lib/std/hash/crc/test.zig
@@ -2,10 +2,29 @@
const std = @import("std");
const testing = std.testing;
-const catalog = @import("catalog.zig");
+const verify = @import("../verify.zig");
+const crc = @import("../crc.zig");
+
+test "crc32 ieee" {
+ inline for ([2]type{ crc.Crc32WithPoly(.IEEE), crc.Crc32SmallWithPoly(.IEEE) }) |ieee| {
+ try testing.expect(ieee.hash("") == 0x00000000);
+ try testing.expect(ieee.hash("a") == 0xe8b7be43);
+ try testing.expect(ieee.hash("abc") == 0x352441c2);
+ try verify.iterativeApi(ieee);
+ }
+}
+
+test "crc32 castagnoli" {
+ inline for ([2]type{ crc.Crc32WithPoly(.Castagnoli), crc.Crc32SmallWithPoly(.Castagnoli) }) |casta| {
+ try testing.expect(casta.hash("") == 0x00000000);
+ try testing.expect(casta.hash("a") == 0xc1d04330);
+ try testing.expect(casta.hash("abc") == 0x364b3fb7);
+ try verify.iterativeApi(casta);
+ }
+}
test "CRC-3/GSM" {
- const Crc3Gsm = catalog.Crc3Gsm;
+ const Crc3Gsm = crc.Crc3Gsm;
try testing.expectEqual(@as(u3, 0x4), Crc3Gsm.hash("123456789"));
@@ -16,7 +35,7 @@ test "CRC-3/GSM" {
}
test "CRC-3/ROHC" {
- const Crc3Rohc = catalog.Crc3Rohc;
+ const Crc3Rohc = crc.Crc3Rohc;
try testing.expectEqual(@as(u3, 0x6), Crc3Rohc.hash("123456789"));
@@ -27,7 +46,7 @@ test "CRC-3/ROHC" {
}
test "CRC-4/G-704" {
- const Crc4G704 = catalog.Crc4G704;
+ const Crc4G704 = crc.Crc4G704;
try testing.expectEqual(@as(u4, 0x7), Crc4G704.hash("123456789"));
@@ -38,7 +57,7 @@ test "CRC-4/G-704" {
}
test "CRC-4/INTERLAKEN" {
- const Crc4Interlaken = catalog.Crc4Interlaken;
+ const Crc4Interlaken = crc.Crc4Interlaken;
try testing.expectEqual(@as(u4, 0xb), Crc4Interlaken.hash("123456789"));
@@ -49,7 +68,7 @@ test "CRC-4/INTERLAKEN" {
}
test "CRC-5/EPC-C1G2" {
- const Crc5EpcC1g2 = catalog.Crc5EpcC1g2;
+ const Crc5EpcC1g2 = crc.Crc5EpcC1g2;
try testing.expectEqual(@as(u5, 0x00), Crc5EpcC1g2.hash("123456789"));
@@ -60,7 +79,7 @@ test "CRC-5/EPC-C1G2" {
}
test "CRC-5/G-704" {
- const Crc5G704 = catalog.Crc5G704;
+ const Crc5G704 = crc.Crc5G704;
try testing.expectEqual(@as(u5, 0x07), Crc5G704.hash("123456789"));
@@ -71,7 +90,7 @@ test "CRC-5/G-704" {
}
test "CRC-5/USB" {
- const Crc5Usb = catalog.Crc5Usb;
+ const Crc5Usb = crc.Crc5Usb;
try testing.expectEqual(@as(u5, 0x19), Crc5Usb.hash("123456789"));
@@ -82,7 +101,7 @@ test "CRC-5/USB" {
}
test "CRC-6/CDMA2000-A" {
- const Crc6Cdma2000A = catalog.Crc6Cdma2000A;
+ const Crc6Cdma2000A = crc.Crc6Cdma2000A;
try testing.expectEqual(@as(u6, 0x0d), Crc6Cdma2000A.hash("123456789"));
@@ -93,7 +112,7 @@ test "CRC-6/CDMA2000-A" {
}
test "CRC-6/CDMA2000-B" {
- const Crc6Cdma2000B = catalog.Crc6Cdma2000B;
+ const Crc6Cdma2000B = crc.Crc6Cdma2000B;
try testing.expectEqual(@as(u6, 0x3b), Crc6Cdma2000B.hash("123456789"));
@@ -104,7 +123,7 @@ test "CRC-6/CDMA2000-B" {
}
test "CRC-6/DARC" {
- const Crc6Darc = catalog.Crc6Darc;
+ const Crc6Darc = crc.Crc6Darc;
try testing.expectEqual(@as(u6, 0x26), Crc6Darc.hash("123456789"));
@@ -115,7 +134,7 @@ test "CRC-6/DARC" {
}
test "CRC-6/G-704" {
- const Crc6G704 = catalog.Crc6G704;
+ const Crc6G704 = crc.Crc6G704;
try testing.expectEqual(@as(u6, 0x06), Crc6G704.hash("123456789"));
@@ -126,7 +145,7 @@ test "CRC-6/G-704" {
}
test "CRC-6/GSM" {
- const Crc6Gsm = catalog.Crc6Gsm;
+ const Crc6Gsm = crc.Crc6Gsm;
try testing.expectEqual(@as(u6, 0x13), Crc6Gsm.hash("123456789"));
@@ -137,7 +156,7 @@ test "CRC-6/GSM" {
}
test "CRC-7/MMC" {
- const Crc7Mmc = catalog.Crc7Mmc;
+ const Crc7Mmc = crc.Crc7Mmc;
try testing.expectEqual(@as(u7, 0x75), Crc7Mmc.hash("123456789"));
@@ -148,7 +167,7 @@ test "CRC-7/MMC" {
}
test "CRC-7/ROHC" {
- const Crc7Rohc = catalog.Crc7Rohc;
+ const Crc7Rohc = crc.Crc7Rohc;
try testing.expectEqual(@as(u7, 0x53), Crc7Rohc.hash("123456789"));
@@ -159,7 +178,7 @@ test "CRC-7/ROHC" {
}
test "CRC-7/UMTS" {
- const Crc7Umts = catalog.Crc7Umts;
+ const Crc7Umts = crc.Crc7Umts;
try testing.expectEqual(@as(u7, 0x61), Crc7Umts.hash("123456789"));
@@ -170,7 +189,7 @@ test "CRC-7/UMTS" {
}
test "CRC-8/AUTOSAR" {
- const Crc8Autosar = catalog.Crc8Autosar;
+ const Crc8Autosar = crc.Crc8Autosar;
try testing.expectEqual(@as(u8, 0xdf), Crc8Autosar.hash("123456789"));
@@ -181,7 +200,7 @@ test "CRC-8/AUTOSAR" {
}
test "CRC-8/BLUETOOTH" {
- const Crc8Bluetooth = catalog.Crc8Bluetooth;
+ const Crc8Bluetooth = crc.Crc8Bluetooth;
try testing.expectEqual(@as(u8, 0x26), Crc8Bluetooth.hash("123456789"));
@@ -192,7 +211,7 @@ test "CRC-8/BLUETOOTH" {
}
test "CRC-8/CDMA2000" {
- const Crc8Cdma2000 = catalog.Crc8Cdma2000;
+ const Crc8Cdma2000 = crc.Crc8Cdma2000;
try testing.expectEqual(@as(u8, 0xda), Crc8Cdma2000.hash("123456789"));
@@ -203,7 +222,7 @@ test "CRC-8/CDMA2000" {
}
test "CRC-8/DARC" {
- const Crc8Darc = catalog.Crc8Darc;
+ const Crc8Darc = crc.Crc8Darc;
try testing.expectEqual(@as(u8, 0x15), Crc8Darc.hash("123456789"));
@@ -214,7 +233,7 @@ test "CRC-8/DARC" {
}
test "CRC-8/DVB-S2" {
- const Crc8DvbS2 = catalog.Crc8DvbS2;
+ const Crc8DvbS2 = crc.Crc8DvbS2;
try testing.expectEqual(@as(u8, 0xbc), Crc8DvbS2.hash("123456789"));
@@ -225,7 +244,7 @@ test "CRC-8/DVB-S2" {
}
test "CRC-8/GSM-A" {
- const Crc8GsmA = catalog.Crc8GsmA;
+ const Crc8GsmA = crc.Crc8GsmA;
try testing.expectEqual(@as(u8, 0x37), Crc8GsmA.hash("123456789"));
@@ -236,7 +255,7 @@ test "CRC-8/GSM-A" {
}
test "CRC-8/GSM-B" {
- const Crc8GsmB = catalog.Crc8GsmB;
+ const Crc8GsmB = crc.Crc8GsmB;
try testing.expectEqual(@as(u8, 0x94), Crc8GsmB.hash("123456789"));
@@ -247,7 +266,7 @@ test "CRC-8/GSM-B" {
}
test "CRC-8/HITAG" {
- const Crc8Hitag = catalog.Crc8Hitag;
+ const Crc8Hitag = crc.Crc8Hitag;
try testing.expectEqual(@as(u8, 0xb4), Crc8Hitag.hash("123456789"));
@@ -258,7 +277,7 @@ test "CRC-8/HITAG" {
}
test "CRC-8/I-432-1" {
- const Crc8I4321 = catalog.Crc8I4321;
+ const Crc8I4321 = crc.Crc8I4321;
try testing.expectEqual(@as(u8, 0xa1), Crc8I4321.hash("123456789"));
@@ -269,7 +288,7 @@ test "CRC-8/I-432-1" {
}
test "CRC-8/I-CODE" {
- const Crc8ICode = catalog.Crc8ICode;
+ const Crc8ICode = crc.Crc8ICode;
try testing.expectEqual(@as(u8, 0x7e), Crc8ICode.hash("123456789"));
@@ -280,7 +299,7 @@ test "CRC-8/I-CODE" {
}
test "CRC-8/LTE" {
- const Crc8Lte = catalog.Crc8Lte;
+ const Crc8Lte = crc.Crc8Lte;
try testing.expectEqual(@as(u8, 0xea), Crc8Lte.hash("123456789"));
@@ -291,7 +310,7 @@ test "CRC-8/LTE" {
}
test "CRC-8/MAXIM-DOW" {
- const Crc8MaximDow = catalog.Crc8MaximDow;
+ const Crc8MaximDow = crc.Crc8MaximDow;
try testing.expectEqual(@as(u8, 0xa1), Crc8MaximDow.hash("123456789"));
@@ -302,7 +321,7 @@ test "CRC-8/MAXIM-DOW" {
}
test "CRC-8/MIFARE-MAD" {
- const Crc8MifareMad = catalog.Crc8MifareMad;
+ const Crc8MifareMad = crc.Crc8MifareMad;
try testing.expectEqual(@as(u8, 0x99), Crc8MifareMad.hash("123456789"));
@@ -313,7 +332,7 @@ test "CRC-8/MIFARE-MAD" {
}
test "CRC-8/NRSC-5" {
- const Crc8Nrsc5 = catalog.Crc8Nrsc5;
+ const Crc8Nrsc5 = crc.Crc8Nrsc5;
try testing.expectEqual(@as(u8, 0xf7), Crc8Nrsc5.hash("123456789"));
@@ -324,7 +343,7 @@ test "CRC-8/NRSC-5" {
}
test "CRC-8/OPENSAFETY" {
- const Crc8Opensafety = catalog.Crc8Opensafety;
+ const Crc8Opensafety = crc.Crc8Opensafety;
try testing.expectEqual(@as(u8, 0x3e), Crc8Opensafety.hash("123456789"));
@@ -335,7 +354,7 @@ test "CRC-8/OPENSAFETY" {
}
test "CRC-8/ROHC" {
- const Crc8Rohc = catalog.Crc8Rohc;
+ const Crc8Rohc = crc.Crc8Rohc;
try testing.expectEqual(@as(u8, 0xd0), Crc8Rohc.hash("123456789"));
@@ -346,7 +365,7 @@ test "CRC-8/ROHC" {
}
test "CRC-8/SAE-J1850" {
- const Crc8SaeJ1850 = catalog.Crc8SaeJ1850;
+ const Crc8SaeJ1850 = crc.Crc8SaeJ1850;
try testing.expectEqual(@as(u8, 0x4b), Crc8SaeJ1850.hash("123456789"));
@@ -357,7 +376,7 @@ test "CRC-8/SAE-J1850" {
}
test "CRC-8/SMBUS" {
- const Crc8Smbus = catalog.Crc8Smbus;
+ const Crc8Smbus = crc.Crc8Smbus;
try testing.expectEqual(@as(u8, 0xf4), Crc8Smbus.hash("123456789"));
@@ -368,7 +387,7 @@ test "CRC-8/SMBUS" {
}
test "CRC-8/TECH-3250" {
- const Crc8Tech3250 = catalog.Crc8Tech3250;
+ const Crc8Tech3250 = crc.Crc8Tech3250;
try testing.expectEqual(@as(u8, 0x97), Crc8Tech3250.hash("123456789"));
@@ -379,7 +398,7 @@ test "CRC-8/TECH-3250" {
}
test "CRC-8/WCDMA" {
- const Crc8Wcdma = catalog.Crc8Wcdma;
+ const Crc8Wcdma = crc.Crc8Wcdma;
try testing.expectEqual(@as(u8, 0x25), Crc8Wcdma.hash("123456789"));
@@ -390,7 +409,7 @@ test "CRC-8/WCDMA" {
}
test "CRC-10/ATM" {
- const Crc10Atm = catalog.Crc10Atm;
+ const Crc10Atm = crc.Crc10Atm;
try testing.expectEqual(@as(u10, 0x199), Crc10Atm.hash("123456789"));
@@ -401,7 +420,7 @@ test "CRC-10/ATM" {
}
test "CRC-10/CDMA2000" {
- const Crc10Cdma2000 = catalog.Crc10Cdma2000;
+ const Crc10Cdma2000 = crc.Crc10Cdma2000;
try testing.expectEqual(@as(u10, 0x233), Crc10Cdma2000.hash("123456789"));
@@ -412,7 +431,7 @@ test "CRC-10/CDMA2000" {
}
test "CRC-10/GSM" {
- const Crc10Gsm = catalog.Crc10Gsm;
+ const Crc10Gsm = crc.Crc10Gsm;
try testing.expectEqual(@as(u10, 0x12a), Crc10Gsm.hash("123456789"));
@@ -423,7 +442,7 @@ test "CRC-10/GSM" {
}
test "CRC-11/FLEXRAY" {
- const Crc11Flexray = catalog.Crc11Flexray;
+ const Crc11Flexray = crc.Crc11Flexray;
try testing.expectEqual(@as(u11, 0x5a3), Crc11Flexray.hash("123456789"));
@@ -434,7 +453,7 @@ test "CRC-11/FLEXRAY" {
}
test "CRC-11/UMTS" {
- const Crc11Umts = catalog.Crc11Umts;
+ const Crc11Umts = crc.Crc11Umts;
try testing.expectEqual(@as(u11, 0x061), Crc11Umts.hash("123456789"));
@@ -445,7 +464,7 @@ test "CRC-11/UMTS" {
}
test "CRC-12/CDMA2000" {
- const Crc12Cdma2000 = catalog.Crc12Cdma2000;
+ const Crc12Cdma2000 = crc.Crc12Cdma2000;
try testing.expectEqual(@as(u12, 0xd4d), Crc12Cdma2000.hash("123456789"));
@@ -456,7 +475,7 @@ test "CRC-12/CDMA2000" {
}
test "CRC-12/DECT" {
- const Crc12Dect = catalog.Crc12Dect;
+ const Crc12Dect = crc.Crc12Dect;
try testing.expectEqual(@as(u12, 0xf5b), Crc12Dect.hash("123456789"));
@@ -467,7 +486,7 @@ test "CRC-12/DECT" {
}
test "CRC-12/GSM" {
- const Crc12Gsm = catalog.Crc12Gsm;
+ const Crc12Gsm = crc.Crc12Gsm;
try testing.expectEqual(@as(u12, 0xb34), Crc12Gsm.hash("123456789"));
@@ -478,7 +497,7 @@ test "CRC-12/GSM" {
}
test "CRC-12/UMTS" {
- const Crc12Umts = catalog.Crc12Umts;
+ const Crc12Umts = crc.Crc12Umts;
try testing.expectEqual(@as(u12, 0xdaf), Crc12Umts.hash("123456789"));
@@ -489,7 +508,7 @@ test "CRC-12/UMTS" {
}
test "CRC-13/BBC" {
- const Crc13Bbc = catalog.Crc13Bbc;
+ const Crc13Bbc = crc.Crc13Bbc;
try testing.expectEqual(@as(u13, 0x04fa), Crc13Bbc.hash("123456789"));
@@ -500,7 +519,7 @@ test "CRC-13/BBC" {
}
test "CRC-14/DARC" {
- const Crc14Darc = catalog.Crc14Darc;
+ const Crc14Darc = crc.Crc14Darc;
try testing.expectEqual(@as(u14, 0x082d), Crc14Darc.hash("123456789"));
@@ -511,7 +530,7 @@ test "CRC-14/DARC" {
}
test "CRC-14/GSM" {
- const Crc14Gsm = catalog.Crc14Gsm;
+ const Crc14Gsm = crc.Crc14Gsm;
try testing.expectEqual(@as(u14, 0x30ae), Crc14Gsm.hash("123456789"));
@@ -522,7 +541,7 @@ test "CRC-14/GSM" {
}
test "CRC-15/CAN" {
- const Crc15Can = catalog.Crc15Can;
+ const Crc15Can = crc.Crc15Can;
try testing.expectEqual(@as(u15, 0x059e), Crc15Can.hash("123456789"));
@@ -533,7 +552,7 @@ test "CRC-15/CAN" {
}
test "CRC-15/MPT1327" {
- const Crc15Mpt1327 = catalog.Crc15Mpt1327;
+ const Crc15Mpt1327 = crc.Crc15Mpt1327;
try testing.expectEqual(@as(u15, 0x2566), Crc15Mpt1327.hash("123456789"));
@@ -544,7 +563,7 @@ test "CRC-15/MPT1327" {
}
test "CRC-16/ARC" {
- const Crc16Arc = catalog.Crc16Arc;
+ const Crc16Arc = crc.Crc16Arc;
try testing.expectEqual(@as(u16, 0xbb3d), Crc16Arc.hash("123456789"));
@@ -555,7 +574,7 @@ test "CRC-16/ARC" {
}
test "CRC-16/CDMA2000" {
- const Crc16Cdma2000 = catalog.Crc16Cdma2000;
+ const Crc16Cdma2000 = crc.Crc16Cdma2000;
try testing.expectEqual(@as(u16, 0x4c06), Crc16Cdma2000.hash("123456789"));
@@ -566,7 +585,7 @@ test "CRC-16/CDMA2000" {
}
test "CRC-16/CMS" {
- const Crc16Cms = catalog.Crc16Cms;
+ const Crc16Cms = crc.Crc16Cms;
try testing.expectEqual(@as(u16, 0xaee7), Crc16Cms.hash("123456789"));
@@ -577,7 +596,7 @@ test "CRC-16/CMS" {
}
test "CRC-16/DDS-110" {
- const Crc16Dds110 = catalog.Crc16Dds110;
+ const Crc16Dds110 = crc.Crc16Dds110;
try testing.expectEqual(@as(u16, 0x9ecf), Crc16Dds110.hash("123456789"));
@@ -588,7 +607,7 @@ test "CRC-16/DDS-110" {
}
test "CRC-16/DECT-R" {
- const Crc16DectR = catalog.Crc16DectR;
+ const Crc16DectR = crc.Crc16DectR;
try testing.expectEqual(@as(u16, 0x007e), Crc16DectR.hash("123456789"));
@@ -599,7 +618,7 @@ test "CRC-16/DECT-R" {
}
test "CRC-16/DECT-X" {
- const Crc16DectX = catalog.Crc16DectX;
+ const Crc16DectX = crc.Crc16DectX;
try testing.expectEqual(@as(u16, 0x007f), Crc16DectX.hash("123456789"));
@@ -610,7 +629,7 @@ test "CRC-16/DECT-X" {
}
test "CRC-16/DNP" {
- const Crc16Dnp = catalog.Crc16Dnp;
+ const Crc16Dnp = crc.Crc16Dnp;
try testing.expectEqual(@as(u16, 0xea82), Crc16Dnp.hash("123456789"));
@@ -621,7 +640,7 @@ test "CRC-16/DNP" {
}
test "CRC-16/EN-13757" {
- const Crc16En13757 = catalog.Crc16En13757;
+ const Crc16En13757 = crc.Crc16En13757;
try testing.expectEqual(@as(u16, 0xc2b7), Crc16En13757.hash("123456789"));
@@ -632,7 +651,7 @@ test "CRC-16/EN-13757" {
}
test "CRC-16/GENIBUS" {
- const Crc16Genibus = catalog.Crc16Genibus;
+ const Crc16Genibus = crc.Crc16Genibus;
try testing.expectEqual(@as(u16, 0xd64e), Crc16Genibus.hash("123456789"));
@@ -643,7 +662,7 @@ test "CRC-16/GENIBUS" {
}
test "CRC-16/GSM" {
- const Crc16Gsm = catalog.Crc16Gsm;
+ const Crc16Gsm = crc.Crc16Gsm;
try testing.expectEqual(@as(u16, 0xce3c), Crc16Gsm.hash("123456789"));
@@ -654,7 +673,7 @@ test "CRC-16/GSM" {
}
test "CRC-16/IBM-3740" {
- const Crc16Ibm3740 = catalog.Crc16Ibm3740;
+ const Crc16Ibm3740 = crc.Crc16Ibm3740;
try testing.expectEqual(@as(u16, 0x29b1), Crc16Ibm3740.hash("123456789"));
@@ -665,7 +684,7 @@ test "CRC-16/IBM-3740" {
}
test "CRC-16/IBM-SDLC" {
- const Crc16IbmSdlc = catalog.Crc16IbmSdlc;
+ const Crc16IbmSdlc = crc.Crc16IbmSdlc;
try testing.expectEqual(@as(u16, 0x906e), Crc16IbmSdlc.hash("123456789"));
@@ -676,7 +695,7 @@ test "CRC-16/IBM-SDLC" {
}
test "CRC-16/ISO-IEC-14443-3-A" {
- const Crc16IsoIec144433A = catalog.Crc16IsoIec144433A;
+ const Crc16IsoIec144433A = crc.Crc16IsoIec144433A;
try testing.expectEqual(@as(u16, 0xbf05), Crc16IsoIec144433A.hash("123456789"));
@@ -687,7 +706,7 @@ test "CRC-16/ISO-IEC-14443-3-A" {
}
test "CRC-16/KERMIT" {
- const Crc16Kermit = catalog.Crc16Kermit;
+ const Crc16Kermit = crc.Crc16Kermit;
try testing.expectEqual(@as(u16, 0x2189), Crc16Kermit.hash("123456789"));
@@ -698,7 +717,7 @@ test "CRC-16/KERMIT" {
}
test "CRC-16/LJ1200" {
- const Crc16Lj1200 = catalog.Crc16Lj1200;
+ const Crc16Lj1200 = crc.Crc16Lj1200;
try testing.expectEqual(@as(u16, 0xbdf4), Crc16Lj1200.hash("123456789"));
@@ -709,7 +728,7 @@ test "CRC-16/LJ1200" {
}
test "CRC-16/M17" {
- const Crc16M17 = catalog.Crc16M17;
+ const Crc16M17 = crc.Crc16M17;
try testing.expectEqual(@as(u16, 0x772b), Crc16M17.hash("123456789"));
@@ -720,7 +739,7 @@ test "CRC-16/M17" {
}
test "CRC-16/MAXIM-DOW" {
- const Crc16MaximDow = catalog.Crc16MaximDow;
+ const Crc16MaximDow = crc.Crc16MaximDow;
try testing.expectEqual(@as(u16, 0x44c2), Crc16MaximDow.hash("123456789"));
@@ -731,7 +750,7 @@ test "CRC-16/MAXIM-DOW" {
}
test "CRC-16/MCRF4XX" {
- const Crc16Mcrf4xx = catalog.Crc16Mcrf4xx;
+ const Crc16Mcrf4xx = crc.Crc16Mcrf4xx;
try testing.expectEqual(@as(u16, 0x6f91), Crc16Mcrf4xx.hash("123456789"));
@@ -742,7 +761,7 @@ test "CRC-16/MCRF4XX" {
}
test "CRC-16/MODBUS" {
- const Crc16Modbus = catalog.Crc16Modbus;
+ const Crc16Modbus = crc.Crc16Modbus;
try testing.expectEqual(@as(u16, 0x4b37), Crc16Modbus.hash("123456789"));
@@ -753,7 +772,7 @@ test "CRC-16/MODBUS" {
}
test "CRC-16/NRSC-5" {
- const Crc16Nrsc5 = catalog.Crc16Nrsc5;
+ const Crc16Nrsc5 = crc.Crc16Nrsc5;
try testing.expectEqual(@as(u16, 0xa066), Crc16Nrsc5.hash("123456789"));
@@ -764,7 +783,7 @@ test "CRC-16/NRSC-5" {
}
test "CRC-16/OPENSAFETY-A" {
- const Crc16OpensafetyA = catalog.Crc16OpensafetyA;
+ const Crc16OpensafetyA = crc.Crc16OpensafetyA;
try testing.expectEqual(@as(u16, 0x5d38), Crc16OpensafetyA.hash("123456789"));
@@ -775,7 +794,7 @@ test "CRC-16/OPENSAFETY-A" {
}
test "CRC-16/OPENSAFETY-B" {
- const Crc16OpensafetyB = catalog.Crc16OpensafetyB;
+ const Crc16OpensafetyB = crc.Crc16OpensafetyB;
try testing.expectEqual(@as(u16, 0x20fe), Crc16OpensafetyB.hash("123456789"));
@@ -786,7 +805,7 @@ test "CRC-16/OPENSAFETY-B" {
}
test "CRC-16/PROFIBUS" {
- const Crc16Profibus = catalog.Crc16Profibus;
+ const Crc16Profibus = crc.Crc16Profibus;
try testing.expectEqual(@as(u16, 0xa819), Crc16Profibus.hash("123456789"));
@@ -797,7 +816,7 @@ test "CRC-16/PROFIBUS" {
}
test "CRC-16/RIELLO" {
- const Crc16Riello = catalog.Crc16Riello;
+ const Crc16Riello = crc.Crc16Riello;
try testing.expectEqual(@as(u16, 0x63d0), Crc16Riello.hash("123456789"));
@@ -808,7 +827,7 @@ test "CRC-16/RIELLO" {
}
test "CRC-16/SPI-FUJITSU" {
- const Crc16SpiFujitsu = catalog.Crc16SpiFujitsu;
+ const Crc16SpiFujitsu = crc.Crc16SpiFujitsu;
try testing.expectEqual(@as(u16, 0xe5cc), Crc16SpiFujitsu.hash("123456789"));
@@ -819,7 +838,7 @@ test "CRC-16/SPI-FUJITSU" {
}
test "CRC-16/T10-DIF" {
- const Crc16T10Dif = catalog.Crc16T10Dif;
+ const Crc16T10Dif = crc.Crc16T10Dif;
try testing.expectEqual(@as(u16, 0xd0db), Crc16T10Dif.hash("123456789"));
@@ -830,7 +849,7 @@ test "CRC-16/T10-DIF" {
}
test "CRC-16/TELEDISK" {
- const Crc16Teledisk = catalog.Crc16Teledisk;
+ const Crc16Teledisk = crc.Crc16Teledisk;
try testing.expectEqual(@as(u16, 0x0fb3), Crc16Teledisk.hash("123456789"));
@@ -841,7 +860,7 @@ test "CRC-16/TELEDISK" {
}
test "CRC-16/TMS37157" {
- const Crc16Tms37157 = catalog.Crc16Tms37157;
+ const Crc16Tms37157 = crc.Crc16Tms37157;
try testing.expectEqual(@as(u16, 0x26b1), Crc16Tms37157.hash("123456789"));
@@ -852,7 +871,7 @@ test "CRC-16/TMS37157" {
}
test "CRC-16/UMTS" {
- const Crc16Umts = catalog.Crc16Umts;
+ const Crc16Umts = crc.Crc16Umts;
try testing.expectEqual(@as(u16, 0xfee8), Crc16Umts.hash("123456789"));
@@ -863,7 +882,7 @@ test "CRC-16/UMTS" {
}
test "CRC-16/USB" {
- const Crc16Usb = catalog.Crc16Usb;
+ const Crc16Usb = crc.Crc16Usb;
try testing.expectEqual(@as(u16, 0xb4c8), Crc16Usb.hash("123456789"));
@@ -874,7 +893,7 @@ test "CRC-16/USB" {
}
test "CRC-16/XMODEM" {
- const Crc16Xmodem = catalog.Crc16Xmodem;
+ const Crc16Xmodem = crc.Crc16Xmodem;
try testing.expectEqual(@as(u16, 0x31c3), Crc16Xmodem.hash("123456789"));
@@ -885,7 +904,7 @@ test "CRC-16/XMODEM" {
}
test "CRC-17/CAN-FD" {
- const Crc17CanFd = catalog.Crc17CanFd;
+ const Crc17CanFd = crc.Crc17CanFd;
try testing.expectEqual(@as(u17, 0x04f03), Crc17CanFd.hash("123456789"));
@@ -896,7 +915,7 @@ test "CRC-17/CAN-FD" {
}
test "CRC-21/CAN-FD" {
- const Crc21CanFd = catalog.Crc21CanFd;
+ const Crc21CanFd = crc.Crc21CanFd;
try testing.expectEqual(@as(u21, 0x0ed841), Crc21CanFd.hash("123456789"));
@@ -907,7 +926,7 @@ test "CRC-21/CAN-FD" {
}
test "CRC-24/BLE" {
- const Crc24Ble = catalog.Crc24Ble;
+ const Crc24Ble = crc.Crc24Ble;
try testing.expectEqual(@as(u24, 0xc25a56), Crc24Ble.hash("123456789"));
@@ -918,7 +937,7 @@ test "CRC-24/BLE" {
}
test "CRC-24/FLEXRAY-A" {
- const Crc24FlexrayA = catalog.Crc24FlexrayA;
+ const Crc24FlexrayA = crc.Crc24FlexrayA;
try testing.expectEqual(@as(u24, 0x7979bd), Crc24FlexrayA.hash("123456789"));
@@ -929,7 +948,7 @@ test "CRC-24/FLEXRAY-A" {
}
test "CRC-24/FLEXRAY-B" {
- const Crc24FlexrayB = catalog.Crc24FlexrayB;
+ const Crc24FlexrayB = crc.Crc24FlexrayB;
try testing.expectEqual(@as(u24, 0x1f23b8), Crc24FlexrayB.hash("123456789"));
@@ -940,7 +959,7 @@ test "CRC-24/FLEXRAY-B" {
}
test "CRC-24/INTERLAKEN" {
- const Crc24Interlaken = catalog.Crc24Interlaken;
+ const Crc24Interlaken = crc.Crc24Interlaken;
try testing.expectEqual(@as(u24, 0xb4f3e6), Crc24Interlaken.hash("123456789"));
@@ -951,7 +970,7 @@ test "CRC-24/INTERLAKEN" {
}
test "CRC-24/LTE-A" {
- const Crc24LteA = catalog.Crc24LteA;
+ const Crc24LteA = crc.Crc24LteA;
try testing.expectEqual(@as(u24, 0xcde703), Crc24LteA.hash("123456789"));
@@ -962,7 +981,7 @@ test "CRC-24/LTE-A" {
}
test "CRC-24/LTE-B" {
- const Crc24LteB = catalog.Crc24LteB;
+ const Crc24LteB = crc.Crc24LteB;
try testing.expectEqual(@as(u24, 0x23ef52), Crc24LteB.hash("123456789"));
@@ -973,7 +992,7 @@ test "CRC-24/LTE-B" {
}
test "CRC-24/OPENPGP" {
- const Crc24Openpgp = catalog.Crc24Openpgp;
+ const Crc24Openpgp = crc.Crc24Openpgp;
try testing.expectEqual(@as(u24, 0x21cf02), Crc24Openpgp.hash("123456789"));
@@ -984,7 +1003,7 @@ test "CRC-24/OPENPGP" {
}
test "CRC-24/OS-9" {
- const Crc24Os9 = catalog.Crc24Os9;
+ const Crc24Os9 = crc.Crc24Os9;
try testing.expectEqual(@as(u24, 0x200fa5), Crc24Os9.hash("123456789"));
@@ -995,7 +1014,7 @@ test "CRC-24/OS-9" {
}
test "CRC-30/CDMA" {
- const Crc30Cdma = catalog.Crc30Cdma;
+ const Crc30Cdma = crc.Crc30Cdma;
try testing.expectEqual(@as(u30, 0x04c34abf), Crc30Cdma.hash("123456789"));
@@ -1006,7 +1025,7 @@ test "CRC-30/CDMA" {
}
test "CRC-31/PHILIPS" {
- const Crc31Philips = catalog.Crc31Philips;
+ const Crc31Philips = crc.Crc31Philips;
try testing.expectEqual(@as(u31, 0x0ce9e46c), Crc31Philips.hash("123456789"));
@@ -1017,7 +1036,7 @@ test "CRC-31/PHILIPS" {
}
test "CRC-32/AIXM" {
- const Crc32Aixm = catalog.Crc32Aixm;
+ const Crc32Aixm = crc.Crc32Aixm;
try testing.expectEqual(@as(u32, 0x3010bf7f), Crc32Aixm.hash("123456789"));
@@ -1028,7 +1047,7 @@ test "CRC-32/AIXM" {
}
test "CRC-32/AUTOSAR" {
- const Crc32Autosar = catalog.Crc32Autosar;
+ const Crc32Autosar = crc.Crc32Autosar;
try testing.expectEqual(@as(u32, 0x1697d06a), Crc32Autosar.hash("123456789"));
@@ -1039,7 +1058,7 @@ test "CRC-32/AUTOSAR" {
}
test "CRC-32/BASE91-D" {
- const Crc32Base91D = catalog.Crc32Base91D;
+ const Crc32Base91D = crc.Crc32Base91D;
try testing.expectEqual(@as(u32, 0x87315576), Crc32Base91D.hash("123456789"));
@@ -1050,7 +1069,7 @@ test "CRC-32/BASE91-D" {
}
test "CRC-32/BZIP2" {
- const Crc32Bzip2 = catalog.Crc32Bzip2;
+ const Crc32Bzip2 = crc.Crc32Bzip2;
try testing.expectEqual(@as(u32, 0xfc891918), Crc32Bzip2.hash("123456789"));
@@ -1061,7 +1080,7 @@ test "CRC-32/BZIP2" {
}
test "CRC-32/CD-ROM-EDC" {
- const Crc32CdRomEdc = catalog.Crc32CdRomEdc;
+ const Crc32CdRomEdc = crc.Crc32CdRomEdc;
try testing.expectEqual(@as(u32, 0x6ec2edc4), Crc32CdRomEdc.hash("123456789"));
@@ -1072,7 +1091,7 @@ test "CRC-32/CD-ROM-EDC" {
}
test "CRC-32/CKSUM" {
- const Crc32Cksum = catalog.Crc32Cksum;
+ const Crc32Cksum = crc.Crc32Cksum;
try testing.expectEqual(@as(u32, 0x765e7680), Crc32Cksum.hash("123456789"));
@@ -1083,7 +1102,7 @@ test "CRC-32/CKSUM" {
}
test "CRC-32/ISCSI" {
- const Crc32Iscsi = catalog.Crc32Iscsi;
+ const Crc32Iscsi = crc.Crc32Iscsi;
try testing.expectEqual(@as(u32, 0xe3069283), Crc32Iscsi.hash("123456789"));
@@ -1094,7 +1113,7 @@ test "CRC-32/ISCSI" {
}
test "CRC-32/ISO-HDLC" {
- const Crc32IsoHdlc = catalog.Crc32IsoHdlc;
+ const Crc32IsoHdlc = crc.Crc32IsoHdlc;
try testing.expectEqual(@as(u32, 0xcbf43926), Crc32IsoHdlc.hash("123456789"));
@@ -1105,7 +1124,7 @@ test "CRC-32/ISO-HDLC" {
}
test "CRC-32/JAMCRC" {
- const Crc32Jamcrc = catalog.Crc32Jamcrc;
+ const Crc32Jamcrc = crc.Crc32Jamcrc;
try testing.expectEqual(@as(u32, 0x340bc6d9), Crc32Jamcrc.hash("123456789"));
@@ -1116,7 +1135,7 @@ test "CRC-32/JAMCRC" {
}
test "CRC-32/MEF" {
- const Crc32Mef = catalog.Crc32Mef;
+ const Crc32Mef = crc.Crc32Mef;
try testing.expectEqual(@as(u32, 0xd2c22f51), Crc32Mef.hash("123456789"));
@@ -1127,7 +1146,7 @@ test "CRC-32/MEF" {
}
test "CRC-32/MPEG-2" {
- const Crc32Mpeg2 = catalog.Crc32Mpeg2;
+ const Crc32Mpeg2 = crc.Crc32Mpeg2;
try testing.expectEqual(@as(u32, 0x0376e6e7), Crc32Mpeg2.hash("123456789"));
@@ -1138,7 +1157,7 @@ test "CRC-32/MPEG-2" {
}
test "CRC-32/XFER" {
- const Crc32Xfer = catalog.Crc32Xfer;
+ const Crc32Xfer = crc.Crc32Xfer;
try testing.expectEqual(@as(u32, 0xbd0be338), Crc32Xfer.hash("123456789"));
@@ -1149,7 +1168,7 @@ test "CRC-32/XFER" {
}
test "CRC-40/GSM" {
- const Crc40Gsm = catalog.Crc40Gsm;
+ const Crc40Gsm = crc.Crc40Gsm;
try testing.expectEqual(@as(u40, 0xd4164fc646), Crc40Gsm.hash("123456789"));
@@ -1160,7 +1179,7 @@ test "CRC-40/GSM" {
}
test "CRC-64/ECMA-182" {
- const Crc64Ecma182 = catalog.Crc64Ecma182;
+ const Crc64Ecma182 = crc.Crc64Ecma182;
try testing.expectEqual(@as(u64, 0x6c40df5f0b497347), Crc64Ecma182.hash("123456789"));
@@ -1171,7 +1190,7 @@ test "CRC-64/ECMA-182" {
}
test "CRC-64/GO-ISO" {
- const Crc64GoIso = catalog.Crc64GoIso;
+ const Crc64GoIso = crc.Crc64GoIso;
try testing.expectEqual(@as(u64, 0xb90956c775a41001), Crc64GoIso.hash("123456789"));
@@ -1182,7 +1201,7 @@ test "CRC-64/GO-ISO" {
}
test "CRC-64/MS" {
- const Crc64Ms = catalog.Crc64Ms;
+ const Crc64Ms = crc.Crc64Ms;
try testing.expectEqual(@as(u64, 0x75d4b74f024eceea), Crc64Ms.hash("123456789"));
@@ -1193,7 +1212,7 @@ test "CRC-64/MS" {
}
test "CRC-64/REDIS" {
- const Crc64Redis = catalog.Crc64Redis;
+ const Crc64Redis = crc.Crc64Redis;
try testing.expectEqual(@as(u64, 0xe9c6d914c4b8d9ca), Crc64Redis.hash("123456789"));
@@ -1204,7 +1223,7 @@ test "CRC-64/REDIS" {
}
test "CRC-64/WE" {
- const Crc64We = catalog.Crc64We;
+ const Crc64We = crc.Crc64We;
try testing.expectEqual(@as(u64, 0x62ec59e3f1a4f00a), Crc64We.hash("123456789"));
@@ -1215,7 +1234,7 @@ test "CRC-64/WE" {
}
test "CRC-64/XZ" {
- const Crc64Xz = catalog.Crc64Xz;
+ const Crc64Xz = crc.Crc64Xz;
try testing.expectEqual(@as(u64, 0x995dc9bbdf1939fa), Crc64Xz.hash("123456789"));
@@ -1226,7 +1245,7 @@ test "CRC-64/XZ" {
}
test "CRC-82/DARC" {
- const Crc82Darc = catalog.Crc82Darc;
+ const Crc82Darc = crc.Crc82Darc;
try testing.expectEqual(@as(u82, 0x09ea83f625023801fd612), Crc82Darc.hash("123456789"));
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
index 2cec73f281..837bdc63c7 100644
--- a/lib/std/http/Client.zig
+++ b/lib/std/http/Client.zig
@@ -771,17 +771,41 @@ pub const Request = struct {
req.client.connection_pool.release(req.client.allocator, req.connection.?);
req.connection = null;
- const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
+ var server_header = std.heap.FixedBufferAllocator.init(req.response.parser.header_bytes_buffer);
+ defer req.response.parser.header_bytes_buffer = server_header.buffer[server_header.end_index..];
+ const protocol, const valid_uri = try validateUri(uri, server_header.allocator());
+
+ const new_host = valid_uri.host.?.raw;
+ const prev_host = req.uri.host.?.raw;
+ const keep_privileged_headers =
+ std.ascii.eqlIgnoreCase(valid_uri.scheme, req.uri.scheme) and
+ std.ascii.endsWithIgnoreCase(new_host, prev_host) and
+ (new_host.len == prev_host.len or new_host[new_host.len - prev_host.len - 1] == '.');
+ if (!keep_privileged_headers) {
+ // When redirecting to a different domain, strip privileged headers.
+ req.privileged_headers = &.{};
+ }
- const port: u16 = uri.port orelse switch (protocol) {
- .plain => 80,
- .tls => 443,
- };
+ if (switch (req.response.status) {
+ .see_other => true,
+ .moved_permanently, .found => req.method == .POST,
+ else => false,
+ }) {
+ // A redirect to a GET must change the method and remove the body.
+ req.method = .GET;
+ req.transfer_encoding = .none;
+ req.headers.content_type = .omit;
+ }
- const host = uri.host orelse return error.UriMissingHost;
+ if (req.transfer_encoding != .none) {
+ // The request body has already been sent. The request is
+ // still in a valid state, but the redirect must be handled
+ // manually.
+ return error.RedirectRequiresResend;
+ }
- req.uri = uri;
- req.connection = try req.client.connect(host, port, protocol);
+ req.uri = valid_uri;
+ req.connection = try req.client.connect(new_host, uriPort(valid_uri, protocol), protocol);
req.redirect_behavior.subtractOne();
req.response.parser.reset();
@@ -796,13 +820,8 @@ pub const Request = struct {
pub const SendError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
- pub const SendOptions = struct {
- /// Specifies that the uri is already escaped.
- raw_uri: bool = false,
- };
-
/// Send the HTTP request headers to the server.
- pub fn send(req: *Request, options: SendOptions) SendError!void {
+ pub fn send(req: *Request) SendError!void {
if (!req.method.requestHasBody() and req.transfer_encoding != .none)
return error.UnsupportedTransferEncoding;
@@ -821,7 +840,6 @@ pub const Request = struct {
.authority = connection.proxied,
.path = true,
.query = true,
- .raw = options.raw_uri,
}, w);
}
try w.writeByte(' ');
@@ -1038,55 +1056,19 @@ pub const Request = struct {
const location = req.response.location orelse
return error.HttpRedirectLocationMissing;
- // This mutates the beginning of header_buffer and uses that
- // for the backing memory of the returned new_uri.
- const header_buffer = req.response.parser.header_bytes_buffer;
- const new_uri = req.uri.resolve_inplace(location, header_buffer) catch
- return error.HttpRedirectLocationInvalid;
-
- // The new URI references the beginning of header_bytes_buffer memory.
- // That memory will be kept, but everything after it will be
- // reused by the subsequent request. In other words,
- // header_bytes_buffer must be large enough to store all
- // redirect locations as well as the final request header.
- const path_end = new_uri.path.ptr + new_uri.path.len;
- // https://github.com/ziglang/zig/issues/1738
- const path_offset = @intFromPtr(path_end) - @intFromPtr(header_buffer.ptr);
- const end_offset = @max(path_offset, location.len);
- req.response.parser.header_bytes_buffer = header_buffer[end_offset..];
-
- const is_same_domain_or_subdomain =
- std.ascii.endsWithIgnoreCase(new_uri.host.?, req.uri.host.?) and
- (new_uri.host.?.len == req.uri.host.?.len or
- new_uri.host.?[new_uri.host.?.len - req.uri.host.?.len - 1] == '.');
-
- if (new_uri.host == null or !is_same_domain_or_subdomain or
- !std.ascii.eqlIgnoreCase(new_uri.scheme, req.uri.scheme))
- {
- // When redirecting to a different domain, strip privileged headers.
- req.privileged_headers = &.{};
- }
-
- if (switch (req.response.status) {
- .see_other => true,
- .moved_permanently, .found => req.method == .POST,
- else => false,
- }) {
- // A redirect to a GET must change the method and remove the body.
- req.method = .GET;
- req.transfer_encoding = .none;
- req.headers.content_type = .omit;
- }
-
- if (req.transfer_encoding != .none) {
- // The request body has already been sent. The request is
- // still in a valid state, but the redirect must be handled
- // manually.
- return error.RedirectRequiresResend;
- }
-
- try req.redirect(new_uri);
- try req.send(.{});
+ // This mutates the beginning of header_bytes_buffer and uses that
+ // for the backing memory of the returned Uri.
+ try req.redirect(req.uri.resolve_inplace(
+ location,
+ &req.response.parser.header_bytes_buffer,
+ ) catch |err| switch (err) {
+ error.UnexpectedCharacter,
+ error.InvalidFormat,
+ error.InvalidPort,
+ => return error.HttpRedirectLocationInvalid,
+ error.NoSpaceLeft => return error.HttpHeadersOversize,
+ });
+ try req.send();
} else {
req.response.skip = false;
if (!req.response.parser.done) {
@@ -1264,30 +1246,25 @@ fn createProxyFromEnvVar(arena: Allocator, env_var_names: []const []const u8) !?
};
} else return null;
- const uri = Uri.parse(content) catch try Uri.parseWithoutScheme(content);
-
- const protocol = if (uri.scheme.len == 0)
- .plain // No scheme, assume http://
- else
- protocol_map.get(uri.scheme) orelse return null; // Unknown scheme, ignore
-
- const host = uri.host orelse return error.HttpProxyMissingHost;
+ const uri = Uri.parse(content) catch try Uri.parseAfterScheme("http", content);
+ const protocol, const valid_uri = validateUri(uri, arena) catch |err| switch (err) {
+ error.UnsupportedUriScheme => return null,
+ error.UriMissingHost => return error.HttpProxyMissingHost,
+ error.OutOfMemory => |e| return e,
+ };
- const authorization: ?[]const u8 = if (uri.user != null or uri.password != null) a: {
- const authorization = try arena.alloc(u8, basic_authorization.valueLengthFromUri(uri));
- assert(basic_authorization.value(uri, authorization).len == authorization.len);
+ const authorization: ?[]const u8 = if (valid_uri.user != null or valid_uri.password != null) a: {
+ const authorization = try arena.alloc(u8, basic_authorization.valueLengthFromUri(valid_uri));
+ assert(basic_authorization.value(valid_uri, authorization).len == authorization.len);
break :a authorization;
} else null;
const proxy = try arena.create(Proxy);
proxy.* = .{
.protocol = protocol,
- .host = host,
+ .host = valid_uri.host.?.raw,
.authorization = authorization,
- .port = uri.port orelse switch (protocol) {
- .plain => 80,
- .tls => 443,
- },
+ .port = uriPort(valid_uri, protocol),
.supports_connect = true,
};
return proxy;
@@ -1305,24 +1282,26 @@ pub const basic_authorization = struct {
}
pub fn valueLengthFromUri(uri: Uri) usize {
- return valueLength(
- if (uri.user) |user| user.len else 0,
- if (uri.password) |password| password.len else 0,
- );
+ var stream = std.io.countingWriter(std.io.null_writer);
+ try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty});
+ const user_len = stream.bytes_written;
+ stream.bytes_written = 0;
+ try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty});
+ const password_len = stream.bytes_written;
+ return valueLength(@intCast(user_len), @intCast(password_len));
}
pub fn value(uri: Uri, out: []u8) []u8 {
- assert(uri.user == null or uri.user.?.len <= max_user_len);
- assert(uri.password == null or uri.password.?.len <= max_password_len);
-
- @memcpy(out[0..prefix.len], prefix);
-
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
- const unencoded = std.fmt.bufPrint(&buf, "{s}:{s}", .{
- uri.user orelse "", uri.password orelse "",
- }) catch unreachable;
- const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], unencoded);
+ var stream = std.io.fixedBufferStream(&buf);
+ stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch
+ unreachable;
+ assert(stream.pos <= max_user_len);
+ stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch
+ unreachable;
+ @memcpy(out[0..prefix.len], prefix);
+ const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], stream.getWritten());
return out[0 .. prefix.len + base64.len];
}
};
@@ -1337,8 +1316,7 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec
.host = host,
.port = port,
.protocol = protocol,
- })) |node|
- return node;
+ })) |node| return node;
if (disable_tls and protocol == .tls)
return error.TlsInitializationFailed;
@@ -1449,19 +1427,12 @@ pub fn connectTunnel(
client.connection_pool.release(client.allocator, conn);
}
- const uri: Uri = .{
+ var buffer: [8096]u8 = undefined;
+ var req = client.open(.CONNECT, .{
.scheme = "http",
- .user = null,
- .password = null,
- .host = tunnel_host,
+ .host = .{ .raw = tunnel_host },
.port = tunnel_port,
- .path = "",
- .query = null,
- .fragment = null,
- };
-
- var buffer: [8096]u8 = undefined;
- var req = client.open(.CONNECT, uri, .{
+ }, .{
.redirect_behavior = .unhandled,
.connection = conn,
.server_header_buffer = &buffer,
@@ -1471,7 +1442,7 @@ pub fn connectTunnel(
};
defer req.deinit();
- req.send(.{ .raw_uri = true }) catch |err| break :tunnel err;
+ req.send() catch |err| break :tunnel err;
req.wait() catch |err| break :tunnel err;
if (req.response.status.class() == .server_error) {
@@ -1500,7 +1471,7 @@ pub fn connectTunnel(
}
// Prevents a dependency loop in open()
-const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused };
+const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUriScheme, ConnectionRefused };
pub const ConnectError = ConnectErrorPartial || RequestError;
/// Connect to `host:port` using the specified protocol. This will reuse a
@@ -1548,7 +1519,7 @@ pub fn connect(
pub const RequestError = ConnectTcpError || ConnectErrorPartial || Request.SendError ||
std.fmt.ParseIntError || Connection.WriteError ||
error{ // TODO: file a zig fmt issue for this bad indentation
- UnsupportedUrlScheme,
+ UnsupportedUriScheme,
UriMissingHost,
CertificateBundleLoadFailure,
@@ -1598,12 +1569,28 @@ pub const RequestOptions = struct {
privileged_headers: []const http.Header = &.{},
};
-pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
- .{ "http", .plain },
- .{ "ws", .plain },
- .{ "https", .tls },
- .{ "wss", .tls },
-});
+fn validateUri(uri: Uri, arena: Allocator) !struct { Connection.Protocol, Uri } {
+ const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
+ .{ "http", .plain },
+ .{ "ws", .plain },
+ .{ "https", .tls },
+ .{ "wss", .tls },
+ });
+ const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUriScheme;
+ var valid_uri = uri;
+ // The host is always going to be needed as a raw string for hostname resolution anyway.
+ valid_uri.host = .{
+ .raw = try (uri.host orelse return error.UriMissingHost).toRawMaybeAlloc(arena),
+ };
+ return .{ protocol, valid_uri };
+}
+
+fn uriPort(uri: Uri, protocol: Connection.Protocol) u16 {
+ return uri.port orelse switch (protocol) {
+ .plain => 80,
+ .tls => 443,
+ };
+}
/// Open a connection to the host specified by `uri` and prepare to send a HTTP request.
///
@@ -1633,14 +1620,8 @@ pub fn open(
}
}
- const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
-
- const port: u16 = uri.port orelse switch (protocol) {
- .plain => 80,
- .tls => 443,
- };
-
- const host = uri.host orelse return error.UriMissingHost;
+ var server_header = std.heap.FixedBufferAllocator.init(options.server_header_buffer);
+ const protocol, const valid_uri = try validateUri(uri, server_header.allocator());
if (protocol == .tls and @atomicLoad(bool, &client.next_https_rescan_certs, .acquire)) {
if (disable_tls) unreachable;
@@ -1649,15 +1630,17 @@ pub fn open(
defer client.ca_bundle_mutex.unlock();
if (client.next_https_rescan_certs) {
- client.ca_bundle.rescan(client.allocator) catch return error.CertificateBundleLoadFailure;
+ client.ca_bundle.rescan(client.allocator) catch
+ return error.CertificateBundleLoadFailure;
@atomicStore(bool, &client.next_https_rescan_certs, false, .release);
}
}
- const conn = options.connection orelse try client.connect(host, port, protocol);
+ const conn = options.connection orelse
+ try client.connect(valid_uri.host.?.raw, uriPort(valid_uri, protocol), protocol);
var req: Request = .{
- .uri = uri,
+ .uri = valid_uri,
.client = client,
.connection = conn,
.keep_alive = options.keep_alive,
@@ -1671,7 +1654,7 @@ pub fn open(
.status = undefined,
.reason = undefined,
.keep_alive = undefined,
- .parser = proto.HeadersParser.init(options.server_header_buffer),
+ .parser = proto.HeadersParser.init(server_header.buffer[server_header.end_index..]),
},
.headers = options.headers,
.extra_headers = options.extra_headers,
@@ -1751,7 +1734,7 @@ pub fn fetch(client: *Client, options: FetchOptions) !FetchResult {
if (options.payload) |payload| req.transfer_encoding = .{ .content_length = payload.len };
- try req.send(.{ .raw_uri = options.raw_uri });
+ try req.send();
if (options.payload) |payload| try req.writeAll(payload);
diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig
index e2aa810d58..caeed0e1ea 100644
--- a/lib/std/http/test.zig
+++ b/lib/std/http/test.zig
@@ -64,7 +64,7 @@ test "trailers" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -474,6 +474,15 @@ test "general client/server API coverage" {
.{ .name = "location", .value = "/redirect/3" },
},
});
+ } else if (mem.eql(u8, request.head.target, "/redirect/5")) {
+ try request.respond("Hello, Redirected!\n", .{
+ .status = .found,
+ .extra_headers = &.{
+ .{ .name = "location", .value = "/%2525" },
+ },
+ });
+ } else if (mem.eql(u8, request.head.target, "/%2525")) {
+ try request.respond("Encoded redirect successful!\n", .{});
} else if (mem.eql(u8, request.head.target, "/redirect/invalid")) {
const invalid_port = try getUnusedTcpPort();
const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}", .{invalid_port});
@@ -529,7 +538,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -554,7 +563,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192 * 1024);
@@ -578,7 +587,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -604,7 +613,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -629,7 +638,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -656,7 +665,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -684,7 +693,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
try std.testing.expectEqual(.ok, req.response.status);
@@ -725,7 +734,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -749,7 +758,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -773,7 +782,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
@@ -797,13 +806,34 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
req.wait() catch |err| switch (err) {
error.TooManyHttpRedirects => {},
else => return err,
};
}
+ { // redirect to encoded url
+ const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/5", .{port});
+ defer gpa.free(location);
+ const uri = try std.Uri.parse(location);
+
+ log.info("{s}", .{location});
+ var server_header_buffer: [1024]u8 = undefined;
+ var req = try client.open(.GET, uri, .{
+ .server_header_buffer = &server_header_buffer,
+ });
+ defer req.deinit();
+
+ try req.send();
+ try req.wait();
+
+ const body = try req.reader().readAllAlloc(gpa, 8192);
+ defer gpa.free(body);
+
+ try expectEqualStrings("Encoded redirect successful!\n", body);
+ }
+
// connection has been kept alive
try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
@@ -819,7 +849,7 @@ test "general client/server API coverage" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
const result = req.wait();
// a proxy without an upstream is likely to return a 5xx status.
@@ -913,16 +943,16 @@ test "Server streams both reading and writing" {
var server_header_buffer: [555]u8 = undefined;
var req = try client.open(.POST, .{
.scheme = "http",
- .host = "127.0.0.1",
+ .host = .{ .raw = "127.0.0.1" },
.port = test_server.port(),
- .path = "/",
+ .path = .{ .percent_encoded = "/" },
}, .{
.server_header_buffer = &server_header_buffer,
});
defer req.deinit();
req.transfer_encoding = .chunked;
- try req.send(.{});
+ try req.send();
try req.wait();
try req.writeAll("one ");
@@ -956,7 +986,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
req.transfer_encoding = .{ .content_length = 14 };
- try req.send(.{});
+ try req.send();
try req.writeAll("Hello, ");
try req.writeAll("World!\n");
try req.finish();
@@ -990,7 +1020,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
req.transfer_encoding = .chunked;
- try req.send(.{});
+ try req.send();
try req.writeAll("Hello, ");
try req.writeAll("World!\n");
try req.finish();
@@ -1044,7 +1074,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
req.transfer_encoding = .chunked;
- try req.send(.{});
+ try req.send();
try req.writeAll("Hello, ");
try req.writeAll("World!\n");
try req.finish();
@@ -1075,7 +1105,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
req.transfer_encoding = .chunked;
- try req.send(.{});
+ try req.send();
try req.wait();
try expectEqual(.expectation_failed, req.response.status);
}
@@ -1180,7 +1210,7 @@ test "redirect to different connection" {
});
defer req.deinit();
- try req.send(.{});
+ try req.send();
try req.wait();
const body = try req.reader().readAllAlloc(gpa, 8192);
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 9f0f444a83..ab89114000 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -413,7 +413,7 @@ pub const StreamSource = @import("io/stream_source.zig").StreamSource;
pub const tty = @import("io/tty.zig");
/// A Writer that doesn't write to anything.
-pub const null_writer = @as(NullWriter, .{ .context = {} });
+pub const null_writer: NullWriter = .{ .context = {} };
const NullWriter = Writer(void, error{}, dummyWrite);
fn dummyWrite(context: void, data: []const u8) error{}!usize {
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index b564d9a99b..93ad1ccbe2 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -3776,19 +3776,19 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
const limb_shift = shift / limb_bits;
const interior_limb_shift = @as(Log2Limb, @truncate(shift));
- var carry: Limb = 0;
var i: usize = 0;
while (i < a.len - limb_shift) : (i += 1) {
- const src_i = a.len - i - 1;
- const dst_i = src_i - limb_shift;
+ const dst_i = i;
+ const src_i = dst_i + limb_shift;
const src_digit = a[src_i];
- r[dst_i] = carry | (src_digit >> interior_limb_shift);
- carry = @call(.always_inline, math.shl, .{
+ const src_digit_next = if (src_i + 1 < a.len) a[src_i + 1] else 0;
+ const carry = @call(.always_inline, math.shl, .{
Limb,
- src_digit,
+ src_digit_next,
limb_bits - @as(Limb, @intCast(interior_limb_shift)),
});
+ r[dst_i] = carry | (src_digit >> interior_limb_shift);
}
}
diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig
index f9d7543c2b..624bdc0b83 100644
--- a/lib/std/math/big/int_test.zig
+++ b/lib/std/math/big/int_test.zig
@@ -2019,6 +2019,19 @@ test "shift-right multi" {
try a.shiftRight(&a, 63);
try a.shiftRight(&a, 2);
try testing.expect(a.eqlZero());
+
+ try a.set(0xffff0000eeee1111dddd2222cccc3333000000000000000000000);
+ try a.shiftRight(&a, 84);
+ const string = try a.toString(
+ testing.allocator,
+ 16,
+ .lower,
+ );
+ defer testing.allocator.free(string);
+ try std.testing.expectEqualStrings(
+ string,
+ "ffff0000eeee1111dddd2222cccc3333",
+ );
}
test "shift-left single" {
diff --git a/lib/std/once.zig b/lib/std/once.zig
index 2f6ee709e2..ee3a8b7a35 100644
--- a/lib/std/once.zig
+++ b/lib/std/once.zig
@@ -7,6 +7,7 @@ pub fn once(comptime f: fn () void) Once(f) {
}
/// An object that executes the function `f` just once.
+/// It is undefined behavior if `f` re-enters the same Once instance.
pub fn Once(comptime f: fn () void) type {
return struct {
done: bool = false,
@@ -51,15 +52,18 @@ test "Once executes its function just once" {
global_once.call();
} else {
var threads: [10]std.Thread = undefined;
- defer for (threads) |handle| handle.join();
+ var thread_count: usize = 0;
+ defer for (threads[0..thread_count]) |handle| handle.join();
for (&threads) |*handle| {
handle.* = try std.Thread.spawn(.{}, struct {
fn thread_fn(x: u8) void {
_ = x;
global_once.call();
+ if (global_number != 1) @panic("memory ordering bug");
}
}.thread_fn, .{0});
+ thread_count += 1;
}
}
diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig
index 1020bef4b7..1847ceb8a1 100644
--- a/lib/std/posix/test.zig
+++ b/lib/std/posix/test.zig
@@ -839,7 +839,7 @@ test "sigaction" {
const S = struct {
var handler_called_count: u32 = 0;
- fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) void {
+ fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) void {
_ = ctx_ptr;
// Check that we received the correct signal.
switch (native_os) {
diff --git a/lib/std/tar.zig b/lib/std/tar.zig
index 2977bc16cc..9dc5bb4a53 100644
--- a/lib/std/tar.zig
+++ b/lib/std/tar.zig
@@ -30,7 +30,7 @@ pub const Diagnostics = struct {
errors: std.ArrayListUnmanaged(Error) = .{},
root_entries: usize = 0,
- root_dir: ?[]const u8 = null,
+ root_dir: []const u8 = "",
pub const Error = union(enum) {
unable_to_create_sym_link: struct {
@@ -55,10 +55,8 @@ pub const Diagnostics = struct {
d.root_dir = try d.allocator.dupe(u8, root_dir);
return;
}
- if (d.root_dir) |r| {
- d.allocator.free(r);
- d.root_dir = null;
- }
+ d.allocator.free(d.root_dir);
+ d.root_dir = "";
}
}
@@ -103,10 +101,7 @@ pub const Diagnostics = struct {
}
}
d.errors.deinit(d.allocator);
- if (d.root_dir) |r| {
- d.allocator.free(r);
- d.root_dir = null;
- }
+ d.allocator.free(d.root_dir);
d.* = undefined;
}
};
@@ -1060,7 +1055,7 @@ test "pipeToFileSystem root_dir" {
};
// there is no root_dir
- try testing.expect(diagnostics.root_dir == null);
+ try testing.expectEqual(0, diagnostics.root_dir.len);
try testing.expectEqual(3, diagnostics.root_entries);
}
@@ -1082,7 +1077,7 @@ test "pipeToFileSystem root_dir" {
};
// root_dir found
- try testing.expectEqualStrings("example", diagnostics.root_dir.?);
+ try testing.expectEqualStrings("example", diagnostics.root_dir);
try testing.expectEqual(1, diagnostics.root_entries);
}
}
diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig
index db082b7f8e..64e8a1c805 100644
--- a/lib/std/zig/Zir.zig
+++ b/lib/std/zig/Zir.zig
@@ -106,12 +106,8 @@ pub const NullTerminatedString = enum(u32) {
/// Given an index into `string_bytes` returns the null-terminated string found there.
pub fn nullTerminatedString(code: Zir, index: NullTerminatedString) [:0]const u8 {
- const start = @intFromEnum(index);
- var end: u32 = start;
- while (code.string_bytes[end] != 0) {
- end += 1;
- }
- return code.string_bytes[start..end :0];
+ const slice = code.string_bytes[@intFromEnum(index)..];
+ return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0];
}
pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index c9fe14a1c6..af0986e0b8 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -988,9 +988,13 @@ fn detectAbiAndDynamicLinker(
// if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead,
// doing the same logic recursively in case it finds another shebang line.
- // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a
- // reasonably reliable path to start with.
- var file_name: []const u8 = "/usr/bin/env";
+ var file_name: []const u8 = switch (os.tag) {
+ // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a
+ // reasonably reliable path to start with.
+ else => "/usr/bin/env",
+ // Haiku does not have a /usr root directory.
+ .haiku => "/bin/env",
+ };
// #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1)
var buffer: [258]u8 = undefined;
while (true) {
diff --git a/lib/std/zig/system/NativePaths.zig b/lib/std/zig/system/NativePaths.zig
index 9d9ab22812..2a50e27b0c 100644
--- a/lib/std/zig/system/NativePaths.zig
+++ b/lib/std/zig/system/NativePaths.zig
@@ -105,6 +105,13 @@ pub fn detect(arena: Allocator, native_target: std.Target) !NativePaths {
return self;
}
+ if (builtin.os.tag == .haiku) {
+ try self.addLibDir("/system/non-packaged/lib");
+ try self.addLibDir("/system/develop/lib");
+ try self.addLibDir("/system/lib");
+ return self;
+ }
+
if (builtin.os.tag != .windows and builtin.os.tag != .wasi) {
const triple = try native_target.linuxTriple(arena);
diff --git a/src/Compilation.zig b/src/Compilation.zig
index c533f2fae7..7af3d7bfd1 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -3159,7 +3159,7 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod
const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
defer gpa.free(rt_file_path);
ref_traces.appendAssumeCapacity(.{
- .decl_name = try eb.addString(ip.stringToSlice(module_reference.decl)),
+ .decl_name = try eb.addString(module_reference.decl.toSlice(ip)),
.src_loc = try eb.addSourceLocation(.{
.src_path = try eb.addString(rt_file_path),
.span_start = span.start,
@@ -3731,24 +3731,24 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
};
defer tar_file.close();
- var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{};
+ var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .{};
defer seen_table.deinit(comp.gpa);
- try seen_table.put(comp.gpa, zcu.main_mod, {});
- try seen_table.put(comp.gpa, zcu.std_mod, {});
+ try seen_table.put(comp.gpa, zcu.main_mod, comp.root_name);
+ try seen_table.put(comp.gpa, zcu.std_mod, zcu.std_mod.fully_qualified_name);
var i: usize = 0;
while (i < seen_table.count()) : (i += 1) {
const mod = seen_table.keys()[i];
- try comp.docsCopyModule(mod, tar_file);
+ try comp.docsCopyModule(mod, seen_table.values()[i], tar_file);
const deps = mod.deps.values();
try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);
- for (deps) |dep| seen_table.putAssumeCapacity(dep, {});
+ for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);
}
}
-fn docsCopyModule(comp: *Compilation, module: *Package.Module, tar_file: std.fs.File) !void {
+fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: std.fs.File) !void {
const root = module.root;
const sub_path = if (root.sub_path.len == 0) "." else root.sub_path;
var mod_dir = root.root_dir.handle.openDir(sub_path, .{ .iterate = true }) catch |err| {
@@ -3788,7 +3788,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, tar_file: std.fs.
var file_header = std.tar.output.Header.init();
file_header.typeflag = .regular;
- try file_header.setPath(module.fully_qualified_name, entry.path);
+ try file_header.setPath(name, entry.path);
try file_header.setSize(stat.size);
try file_header.updateChecksum();
@@ -4074,8 +4074,7 @@ fn workerCheckEmbedFile(
fn detectEmbedFileUpdate(comp: *Compilation, embed_file: *Module.EmbedFile) !void {
const mod = comp.module.?;
const ip = &mod.intern_pool;
- const sub_file_path = ip.stringToSlice(embed_file.sub_file_path);
- var file = try embed_file.owner.root.openFile(sub_file_path, .{});
+ var file = try embed_file.owner.root.openFile(embed_file.sub_file_path.toSlice(ip), .{});
defer file.close();
const stat = try file.stat();
@@ -4444,7 +4443,7 @@ fn reportRetryableEmbedFileError(
const ip = &mod.intern_pool;
const err_msg = try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{}{s}': {s}", .{
embed_file.owner.root,
- ip.stringToSlice(embed_file.sub_file_path),
+ embed_file.sub_file_path.toSlice(ip),
@errorName(err),
});
diff --git a/src/InternPool.zig b/src/InternPool.zig
index 1155d8c5ad..15dba62e07 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -351,7 +351,7 @@ const KeyAdapter = struct {
pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
_ = b_void;
if (ctx.intern_pool.items.items(.tag)[b_map_index] == .removed) return false;
- return ctx.intern_pool.indexToKey(@as(Index, @enumFromInt(b_map_index))).eql(a, ctx.intern_pool);
+ return ctx.intern_pool.indexToKey(@enumFromInt(b_map_index)).eql(a, ctx.intern_pool);
}
pub fn hash(ctx: @This(), a: Key) u32 {
@@ -385,7 +385,7 @@ pub const RuntimeIndex = enum(u32) {
_,
pub fn increment(ri: *RuntimeIndex) void {
- ri.* = @as(RuntimeIndex, @enumFromInt(@intFromEnum(ri.*) + 1));
+ ri.* = @enumFromInt(@intFromEnum(ri.*) + 1);
}
};
@@ -418,12 +418,44 @@ pub const OptionalNamespaceIndex = enum(u32) {
/// An index into `string_bytes`.
pub const String = enum(u32) {
+ /// An empty string.
+ empty = 0,
+ _,
+
+ pub fn toSlice(string: String, len: u64, ip: *const InternPool) []const u8 {
+ return ip.string_bytes.items[@intFromEnum(string)..][0..@intCast(len)];
+ }
+
+ pub fn at(string: String, index: u64, ip: *const InternPool) u8 {
+ return ip.string_bytes.items[@intCast(@intFromEnum(string) + index)];
+ }
+
+ pub fn toNullTerminatedString(string: String, len: u64, ip: *const InternPool) NullTerminatedString {
+ assert(std.mem.indexOfScalar(u8, string.toSlice(len, ip), 0) == null);
+ assert(string.at(len, ip) == 0);
+ return @enumFromInt(@intFromEnum(string));
+ }
+};
+
+/// An index into `string_bytes` which might be `none`.
+pub const OptionalString = enum(u32) {
+ /// This is distinct from `none` - it is a valid index that represents empty string.
+ empty = 0,
+ none = std.math.maxInt(u32),
_,
+
+ pub fn unwrap(string: OptionalString) ?String {
+ return if (string != .none) @enumFromInt(@intFromEnum(string)) else null;
+ }
+
+ pub fn toSlice(string: OptionalString, len: u64, ip: *const InternPool) ?[]const u8 {
+ return (string.unwrap() orelse return null).toSlice(len, ip);
+ }
};
/// An index into `string_bytes`.
pub const NullTerminatedString = enum(u32) {
- /// This is distinct from `none` - it is a valid index that represents empty string.
+ /// An empty string.
empty = 0,
_,
@@ -447,6 +479,19 @@ pub const NullTerminatedString = enum(u32) {
return @enumFromInt(@intFromEnum(self));
}
+ pub fn toSlice(string: NullTerminatedString, ip: *const InternPool) [:0]const u8 {
+ const slice = ip.string_bytes.items[@intFromEnum(string)..];
+ return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0];
+ }
+
+ pub fn length(string: NullTerminatedString, ip: *const InternPool) u32 {
+ return @intCast(string.toSlice(ip).len);
+ }
+
+ pub fn eqlSlice(string: NullTerminatedString, slice: []const u8, ip: *const InternPool) bool {
+ return std.mem.eql(u8, string.toSlice(ip), slice);
+ }
+
const Adapter = struct {
strings: []const NullTerminatedString,
@@ -467,11 +512,11 @@ pub const NullTerminatedString = enum(u32) {
return @intFromEnum(a) < @intFromEnum(b);
}
- pub fn toUnsigned(self: NullTerminatedString, ip: *const InternPool) ?u32 {
- const s = ip.stringToSlice(self);
- if (s.len > 1 and s[0] == '0') return null;
- if (std.mem.indexOfScalar(u8, s, '_')) |_| return null;
- return std.fmt.parseUnsigned(u32, s, 10) catch null;
+ pub fn toUnsigned(string: NullTerminatedString, ip: *const InternPool) ?u32 {
+ const slice = string.toSlice(ip);
+ if (slice.len > 1 and slice[0] == '0') return null;
+ if (std.mem.indexOfScalar(u8, slice, '_')) |_| return null;
+ return std.fmt.parseUnsigned(u32, slice, 10) catch null;
}
const FormatData = struct {
@@ -484,11 +529,11 @@ pub const NullTerminatedString = enum(u32) {
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
- const s = data.ip.stringToSlice(data.string);
+ const slice = data.string.toSlice(data.ip);
if (comptime std.mem.eql(u8, specifier, "")) {
- try writer.writeAll(s);
+ try writer.writeAll(slice);
} else if (comptime std.mem.eql(u8, specifier, "i")) {
- try writer.print("{p}", .{std.zig.fmtId(s)});
+ try writer.print("{p}", .{std.zig.fmtId(slice)});
} else @compileError("invalid format string '" ++ specifier ++ "' for '" ++ @typeName(NullTerminatedString) ++ "'");
}
@@ -504,9 +549,12 @@ pub const OptionalNullTerminatedString = enum(u32) {
none = std.math.maxInt(u32),
_,
- pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString {
- if (oi == .none) return null;
- return @enumFromInt(@intFromEnum(oi));
+ pub fn unwrap(string: OptionalNullTerminatedString) ?NullTerminatedString {
+ return if (string != .none) @enumFromInt(@intFromEnum(string)) else null;
+ }
+
+ pub fn toSlice(string: OptionalNullTerminatedString, ip: *const InternPool) ?[:0]const u8 {
+ return (string.unwrap() orelse return null).toSlice(ip);
}
};
@@ -690,6 +738,10 @@ pub const Key = union(enum) {
len: u64,
child: Index,
sentinel: Index = .none,
+
+ pub fn lenIncludingSentinel(array_type: ArrayType) u64 {
+ return array_type.len + @intFromBool(array_type.sentinel != .none);
+ }
};
/// Extern so that hashing can be done via memory reinterpreting.
@@ -1043,7 +1095,7 @@ pub const Key = union(enum) {
storage: Storage,
pub const Storage = union(enum) {
- bytes: []const u8,
+ bytes: String,
elems: []const Index,
repeated_elem: Index,
@@ -1203,7 +1255,7 @@ pub const Key = union(enum) {
if (child == .u8_type) {
switch (aggregate.storage) {
- .bytes => |bytes| for (bytes[0..@intCast(len)]) |byte| {
+ .bytes => |bytes| for (bytes.toSlice(len, ip)) |byte| {
std.hash.autoHash(&hasher, KeyTag.int);
std.hash.autoHash(&hasher, byte);
},
@@ -1240,7 +1292,7 @@ pub const Key = union(enum) {
switch (aggregate.storage) {
.bytes => unreachable,
- .elems => |elems| for (elems[0..@as(usize, @intCast(len))]) |elem|
+ .elems => |elems| for (elems[0..@intCast(len)]) |elem|
std.hash.autoHash(&hasher, elem),
.repeated_elem => |elem| {
var remaining = len;
@@ -1505,11 +1557,11 @@ pub const Key = union(enum) {
if (a_info.ty == .c_longdouble_type and a_info.storage != .f80) {
// These are strange: we'll sometimes represent them as f128, even if the
// underlying type is smaller. f80 is an exception: see float_c_longdouble_f80.
- const a_val = switch (a_info.storage) {
- inline else => |val| @as(u128, @bitCast(@as(f128, @floatCast(val)))),
+ const a_val: u128 = switch (a_info.storage) {
+ inline else => |val| @bitCast(@as(f128, @floatCast(val))),
};
- const b_val = switch (b_info.storage) {
- inline else => |val| @as(u128, @bitCast(@as(f128, @floatCast(val)))),
+ const b_val: u128 = switch (b_info.storage) {
+ inline else => |val| @bitCast(@as(f128, @floatCast(val))),
};
return a_val == b_val;
}
@@ -1560,11 +1612,11 @@ pub const Key = union(enum) {
const len = ip.aggregateTypeLen(a_info.ty);
const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?;
if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) {
- for (0..@as(usize, @intCast(len))) |elem_index| {
+ for (0..@intCast(len)) |elem_index| {
const a_elem = switch (a_info.storage) {
.bytes => |bytes| ip.getIfExists(.{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = bytes[elem_index] },
+ .storage = .{ .u64 = bytes.at(elem_index, ip) },
} }) orelse return false,
.elems => |elems| elems[elem_index],
.repeated_elem => |elem| elem,
@@ -1572,7 +1624,7 @@ pub const Key = union(enum) {
const b_elem = switch (b_info.storage) {
.bytes => |bytes| ip.getIfExists(.{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = bytes[elem_index] },
+ .storage = .{ .u64 = bytes.at(elem_index, ip) },
} }) orelse return false,
.elems => |elems| elems[elem_index],
.repeated_elem => |elem| elem,
@@ -1585,18 +1637,15 @@ pub const Key = union(enum) {
switch (a_info.storage) {
.bytes => |a_bytes| {
const b_bytes = b_info.storage.bytes;
- return std.mem.eql(
- u8,
- a_bytes[0..@as(usize, @intCast(len))],
- b_bytes[0..@as(usize, @intCast(len))],
- );
+ return a_bytes == b_bytes or
+ std.mem.eql(u8, a_bytes.toSlice(len, ip), b_bytes.toSlice(len, ip));
},
.elems => |a_elems| {
const b_elems = b_info.storage.elems;
return std.mem.eql(
Index,
- a_elems[0..@as(usize, @intCast(len))],
- b_elems[0..@as(usize, @intCast(len))],
+ a_elems[0..@intCast(len)],
+ b_elems[0..@intCast(len)],
);
},
.repeated_elem => |a_elem| {
@@ -4175,10 +4224,10 @@ pub const Float64 = struct {
}
fn pack(val: f64) Float64 {
- const bits = @as(u64, @bitCast(val));
+ const bits: u64 = @bitCast(val);
return .{
- .piece0 = @as(u32, @truncate(bits)),
- .piece1 = @as(u32, @truncate(bits >> 32)),
+ .piece0 = @truncate(bits),
+ .piece1 = @truncate(bits >> 32),
};
}
};
@@ -4197,11 +4246,11 @@ pub const Float80 = struct {
}
fn pack(val: f80) Float80 {
- const bits = @as(u80, @bitCast(val));
+ const bits: u80 = @bitCast(val);
return .{
- .piece0 = @as(u32, @truncate(bits)),
- .piece1 = @as(u32, @truncate(bits >> 32)),
- .piece2 = @as(u16, @truncate(bits >> 64)),
+ .piece0 = @truncate(bits),
+ .piece1 = @truncate(bits >> 32),
+ .piece2 = @truncate(bits >> 64),
};
}
};
@@ -4222,12 +4271,12 @@ pub const Float128 = struct {
}
fn pack(val: f128) Float128 {
- const bits = @as(u128, @bitCast(val));
+ const bits: u128 = @bitCast(val);
return .{
- .piece0 = @as(u32, @truncate(bits)),
- .piece1 = @as(u32, @truncate(bits >> 32)),
- .piece2 = @as(u32, @truncate(bits >> 64)),
- .piece3 = @as(u32, @truncate(bits >> 96)),
+ .piece0 = @truncate(bits),
+ .piece1 = @truncate(bits >> 32),
+ .piece2 = @truncate(bits >> 64),
+ .piece3 = @truncate(bits >> 96),
};
}
};
@@ -4244,7 +4293,7 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void {
assert(ip.items.len == 0);
// Reserve string index 0 for an empty string.
- assert((try ip.getOrPutString(gpa, "")) == .empty);
+ assert((try ip.getOrPutString(gpa, "", .no_embedded_nulls)) == .empty);
// So that we can use `catch unreachable` below.
try ip.items.ensureUnusedCapacity(gpa, static_keys.len);
@@ -4329,13 +4378,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.type_int_signed => .{
.int_type = .{
.signedness = .signed,
- .bits = @as(u16, @intCast(data)),
+ .bits = @intCast(data),
},
},
.type_int_unsigned => .{
.int_type = .{
.signedness = .unsigned,
- .bits = @as(u16, @intCast(data)),
+ .bits = @intCast(data),
},
},
.type_array_big => {
@@ -4354,8 +4403,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.sentinel = .none,
} };
},
- .simple_type => .{ .simple_type = @as(SimpleType, @enumFromInt(data)) },
- .simple_value => .{ .simple_value = @as(SimpleValue, @enumFromInt(data)) },
+ .simple_type => .{ .simple_type = @enumFromInt(data) },
+ .simple_value => .{ .simple_value = @enumFromInt(data) },
.type_vector => {
const vector_info = ip.extraData(Vector, data);
@@ -4506,9 +4555,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} },
.type_function => .{ .func_type = ip.extraFuncType(data) },
- .undef => .{ .undef = @as(Index, @enumFromInt(data)) },
+ .undef => .{ .undef = @enumFromInt(data) },
.opt_null => .{ .opt = .{
- .ty = @as(Index, @enumFromInt(data)),
+ .ty = @enumFromInt(data),
.val = .none,
} },
.opt_payload => {
@@ -4670,11 +4719,11 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
},
.float_f16 => .{ .float = .{
.ty = .f16_type,
- .storage = .{ .f16 = @as(f16, @bitCast(@as(u16, @intCast(data)))) },
+ .storage = .{ .f16 = @bitCast(@as(u16, @intCast(data))) },
} },
.float_f32 => .{ .float = .{
.ty = .f32_type,
- .storage = .{ .f32 = @as(f32, @bitCast(data)) },
+ .storage = .{ .f32 = @bitCast(data) },
} },
.float_f64 => .{ .float = .{
.ty = .f64_type,
@@ -4771,10 +4820,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
},
.bytes => {
const extra = ip.extraData(Bytes, data);
- const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.ty));
return .{ .aggregate = .{
.ty = extra.ty,
- .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] },
+ .storage = .{ .bytes = extra.bytes },
} };
},
.aggregate => {
@@ -4809,14 +4857,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.val = .{ .payload = extra.val },
} };
},
- .enum_literal => .{ .enum_literal = @as(NullTerminatedString, @enumFromInt(data)) },
+ .enum_literal => .{ .enum_literal = @enumFromInt(data) },
.enum_tag => .{ .enum_tag = ip.extraData(Tag.EnumTag, data) },
.memoized_call => {
const extra = ip.extraDataTrail(MemoizedCall, data);
return .{ .memoized_call = .{
.func = extra.data.func,
- .arg_values = @as([]const Index, @ptrCast(ip.extra.items[extra.end..][0..extra.data.args_len])),
+ .arg_values = @ptrCast(ip.extra.items[extra.end..][0..extra.data.args_len]),
.result = extra.data.result,
} };
},
@@ -5596,9 +5644,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
switch (aggregate.storage) {
.bytes => |bytes| {
assert(child == .u8_type);
- if (bytes.len != len) {
- assert(bytes.len == len_including_sentinel);
- assert(bytes[@intCast(len)] == ip.indexToKey(sentinel).int.storage.u64);
+ if (sentinel != .none) {
+ assert(bytes.at(@intCast(len), ip) == ip.indexToKey(sentinel).int.storage.u64);
}
},
.elems => |elems| {
@@ -5641,11 +5688,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
switch (ty_key) {
.anon_struct_type => |anon_struct_type| opv: {
switch (aggregate.storage) {
- .bytes => |bytes| for (anon_struct_type.values.get(ip), bytes) |value, byte| {
- if (value != ip.getIfExists(.{ .int = .{
- .ty = .u8_type,
- .storage = .{ .u64 = byte },
- } })) break :opv;
+ .bytes => |bytes| for (anon_struct_type.values.get(ip), bytes.at(0, ip)..) |value, byte| {
+ if (value == .none) break :opv;
+ switch (ip.indexToKey(value)) {
+ .undef => break :opv,
+ .int => |int| switch (int.storage) {
+ .u64 => |x| if (x != byte) break :opv,
+ else => break :opv,
+ },
+ else => unreachable,
+ }
},
.elems => |elems| if (!std.mem.eql(
Index,
@@ -5670,9 +5722,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
repeated: {
switch (aggregate.storage) {
- .bytes => |bytes| for (bytes[1..@as(usize, @intCast(len))]) |byte|
- if (byte != bytes[0]) break :repeated,
- .elems => |elems| for (elems[1..@as(usize, @intCast(len))]) |elem|
+ .bytes => |bytes| for (bytes.toSlice(len, ip)[1..]) |byte|
+ if (byte != bytes.at(0, ip)) break :repeated,
+ .elems => |elems| for (elems[1..@intCast(len)]) |elem|
if (elem != elems[0]) break :repeated,
.repeated_elem => {},
}
@@ -5681,7 +5733,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
_ = ip.map.pop();
const elem = try ip.get(gpa, .{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = bytes[0] },
+ .storage = .{ .u64 = bytes.at(0, ip) },
} });
assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
try ip.items.ensureUnusedCapacity(gpa, 1);
@@ -5710,7 +5762,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
try ip.string_bytes.ensureUnusedCapacity(gpa, @intCast(len_including_sentinel + 1));
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
switch (aggregate.storage) {
- .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes[0..@intCast(len)]),
+ .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes.toSlice(len, ip)),
.elems => |elems| for (elems[0..@intCast(len)]) |elem| switch (ip.indexToKey(elem)) {
.undef => {
ip.string_bytes.shrinkRetainingCapacity(string_bytes_index);
@@ -5730,15 +5782,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
else => unreachable,
},
}
- const has_internal_null =
- std.mem.indexOfScalar(u8, ip.string_bytes.items[string_bytes_index..], 0) != null;
if (sentinel != .none) ip.string_bytes.appendAssumeCapacity(
@intCast(ip.indexToKey(sentinel).int.storage.u64),
);
- const string: String = if (has_internal_null)
- @enumFromInt(string_bytes_index)
- else
- (try ip.getOrPutTrailingString(gpa, @intCast(len_including_sentinel))).toString();
+ const string = try ip.getOrPutTrailingString(
+ gpa,
+ @intCast(len_including_sentinel),
+ .maybe_embedded_nulls,
+ );
ip.items.appendAssumeCapacity(.{
.tag = .bytes,
.data = ip.addExtraAssumeCapacity(Bytes{
@@ -5780,7 +5831,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.tag = .memoized_call,
.data = ip.addExtraAssumeCapacity(MemoizedCall{
.func = memoized_call.func,
- .args_len = @as(u32, @intCast(memoized_call.arg_values.len)),
+ .args_len = @intCast(memoized_call.arg_values.len),
.result = memoized_call.result,
}),
});
@@ -6753,7 +6804,7 @@ fn finishFuncInstance(
const decl = ip.declPtr(decl_index);
decl.name = try ip.getOrPutStringFmt(gpa, "{}__anon_{d}", .{
fn_owner_decl.name.fmt(ip), @intFromEnum(decl_index),
- });
+ }, .no_embedded_nulls);
return func_index;
}
@@ -7216,7 +7267,7 @@ pub fn remove(ip: *InternPool, index: Index) void {
}
fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void {
- const limbs_len = @as(u32, @intCast(limbs.len));
+ const limbs_len: u32 = @intCast(limbs.len);
try ip.reserveLimbs(gpa, @typeInfo(Int).Struct.fields.len + limbs_len);
ip.items.appendAssumeCapacity(.{
.tag = tag,
@@ -7235,7 +7286,7 @@ fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32
}
fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
- const result = @as(u32, @intCast(ip.extra.items.len));
+ const result: u32 = @intCast(ip.extra.items.len);
inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
ip.extra.appendAssumeCapacity(switch (field.type) {
Index,
@@ -7286,7 +7337,7 @@ fn addLimbsExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
@sizeOf(u64) => {},
else => @compileError("unsupported host"),
}
- const result = @as(u32, @intCast(ip.limbs.items.len));
+ const result: u32 = @intCast(ip.limbs.items.len);
inline for (@typeInfo(@TypeOf(extra)).Struct.fields, 0..) |field, i| {
const new: u32 = switch (field.type) {
u32 => @field(extra, field.name),
@@ -7374,7 +7425,7 @@ fn limbData(ip: *const InternPool, comptime T: type, index: usize) T {
@field(result, field.name) = switch (field.type) {
u32 => int32,
- Index => @as(Index, @enumFromInt(int32)),
+ Index => @enumFromInt(int32),
else => @compileError("bad field type: " ++ @typeName(field.type)),
};
}
@@ -7410,8 +7461,8 @@ fn limbsSliceToIndex(ip: *const InternPool, limbs: []const Limb) LimbsAsIndexes
};
// TODO: https://github.com/ziglang/zig/issues/1738
return .{
- .start = @as(u32, @intCast(@divExact(@intFromPtr(limbs.ptr) - @intFromPtr(host_slice.ptr), @sizeOf(Limb)))),
- .len = @as(u32, @intCast(limbs.len)),
+ .start = @intCast(@divExact(@intFromPtr(limbs.ptr) - @intFromPtr(host_slice.ptr), @sizeOf(Limb))),
+ .len = @intCast(limbs.len),
};
}
@@ -7683,7 +7734,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
.val = error_union.val,
} }),
.aggregate => |aggregate| {
- const new_len = @as(usize, @intCast(ip.aggregateTypeLen(new_ty)));
+ const new_len: usize = @intCast(ip.aggregateTypeLen(new_ty));
direct: {
const old_ty_child = switch (ip.indexToKey(old_ty)) {
inline .array_type, .vector_type => |seq_type| seq_type.child,
@@ -7696,16 +7747,11 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
else => unreachable,
};
if (old_ty_child != new_ty_child) break :direct;
- // TODO: write something like getCoercedInts to avoid needing to dupe here
switch (aggregate.storage) {
- .bytes => |bytes| {
- const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]);
- defer gpa.free(bytes_copy);
- return ip.get(gpa, .{ .aggregate = .{
- .ty = new_ty,
- .storage = .{ .bytes = bytes_copy },
- } });
- },
+ .bytes => |bytes| return ip.get(gpa, .{ .aggregate = .{
+ .ty = new_ty,
+ .storage = .{ .bytes = bytes },
+ } }),
.elems => |elems| {
const elems_copy = try gpa.dupe(Index, elems[0..new_len]);
defer gpa.free(elems_copy);
@@ -7729,14 +7775,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
// lifetime issues, since it'll allow us to avoid referencing `aggregate` after we
// begin interning elems.
switch (aggregate.storage) {
- .bytes => {
+ .bytes => |bytes| {
// We have to intern each value here, so unfortunately we can't easily avoid
// the repeated indexToKey calls.
- for (agg_elems, 0..) |*elem, i| {
- const x = ip.indexToKey(val).aggregate.storage.bytes[i];
+ for (agg_elems, 0..) |*elem, index| {
elem.* = try ip.get(gpa, .{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = x },
+ .storage = .{ .u64 = bytes.at(index, ip) },
} });
}
},
@@ -8169,9 +8214,8 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
.bytes => b: {
const info = ip.extraData(Bytes, data);
- const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(info.ty)));
- break :b @sizeOf(Bytes) + len +
- @intFromBool(ip.string_bytes.items[@intFromEnum(info.bytes) + len - 1] != 0);
+ const len: usize = @intCast(ip.aggregateTypeLenIncludingSentinel(info.ty));
+ break :b @sizeOf(Bytes) + len + @intFromBool(info.bytes.at(len - 1, ip) != 0);
},
.aggregate => b: {
const info = ip.extraData(Tag.Aggregate, data);
@@ -8434,15 +8478,35 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)
};
}
+const EmbeddedNulls = enum {
+ no_embedded_nulls,
+ maybe_embedded_nulls,
+
+ fn StringType(comptime embedded_nulls: EmbeddedNulls) type {
+ return switch (embedded_nulls) {
+ .no_embedded_nulls => NullTerminatedString,
+ .maybe_embedded_nulls => String,
+ };
+ }
+
+ fn OptionalStringType(comptime embedded_nulls: EmbeddedNulls) type {
+ return switch (embedded_nulls) {
+ .no_embedded_nulls => OptionalNullTerminatedString,
+ .maybe_embedded_nulls => OptionalString,
+ };
+ }
+};
+
pub fn getOrPutString(
ip: *InternPool,
gpa: Allocator,
- s: []const u8,
-) Allocator.Error!NullTerminatedString {
- try ip.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
- ip.string_bytes.appendSliceAssumeCapacity(s);
+ slice: []const u8,
+ comptime embedded_nulls: EmbeddedNulls,
+) Allocator.Error!embedded_nulls.StringType() {
+ try ip.string_bytes.ensureUnusedCapacity(gpa, slice.len + 1);
+ ip.string_bytes.appendSliceAssumeCapacity(slice);
ip.string_bytes.appendAssumeCapacity(0);
- return ip.getOrPutTrailingString(gpa, s.len + 1);
+ return ip.getOrPutTrailingString(gpa, slice.len + 1, embedded_nulls);
}
pub fn getOrPutStringFmt(
@@ -8450,23 +8514,24 @@ pub fn getOrPutStringFmt(
gpa: Allocator,
comptime format: []const u8,
args: anytype,
-) Allocator.Error!NullTerminatedString {
+ comptime embedded_nulls: EmbeddedNulls,
+) Allocator.Error!embedded_nulls.StringType() {
// ensure that references to string_bytes in args do not get invalidated
const len: usize = @intCast(std.fmt.count(format, args) + 1);
try ip.string_bytes.ensureUnusedCapacity(gpa, len);
ip.string_bytes.writer(undefined).print(format, args) catch unreachable;
ip.string_bytes.appendAssumeCapacity(0);
- return ip.getOrPutTrailingString(gpa, len);
+ return ip.getOrPutTrailingString(gpa, len, embedded_nulls);
}
pub fn getOrPutStringOpt(
ip: *InternPool,
gpa: Allocator,
- optional_string: ?[]const u8,
-) Allocator.Error!OptionalNullTerminatedString {
- const s = optional_string orelse return .none;
- const interned = try getOrPutString(ip, gpa, s);
- return interned.toOptional();
+ slice: ?[]const u8,
+ comptime embedded_nulls: EmbeddedNulls,
+) Allocator.Error!embedded_nulls.OptionalStringType() {
+ const string = try getOrPutString(ip, gpa, slice orelse return .none, embedded_nulls);
+ return string.toOptional();
}
/// Uses the last len bytes of ip.string_bytes as the key.
@@ -8474,7 +8539,8 @@ pub fn getOrPutTrailingString(
ip: *InternPool,
gpa: Allocator,
len: usize,
-) Allocator.Error!NullTerminatedString {
+ comptime embedded_nulls: EmbeddedNulls,
+) Allocator.Error!embedded_nulls.StringType() {
const string_bytes = &ip.string_bytes;
const str_index: u32 = @intCast(string_bytes.items.len - len);
if (len > 0 and string_bytes.getLast() == 0) {
@@ -8483,6 +8549,14 @@ pub fn getOrPutTrailingString(
try string_bytes.ensureUnusedCapacity(gpa, 1);
}
const key: []const u8 = string_bytes.items[str_index..];
+ const has_embedded_null = std.mem.indexOfScalar(u8, key, 0) != null;
+ switch (embedded_nulls) {
+ .no_embedded_nulls => assert(!has_embedded_null),
+ .maybe_embedded_nulls => if (has_embedded_null) {
+ string_bytes.appendAssumeCapacity(0);
+ return @enumFromInt(str_index);
+ },
+ }
const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{
.bytes = string_bytes,
}, std.hash_map.StringIndexContext{
@@ -8498,58 +8572,10 @@ pub fn getOrPutTrailingString(
}
}
-/// Uses the last len bytes of ip.string_bytes as the key.
-pub fn getTrailingAggregate(
- ip: *InternPool,
- gpa: Allocator,
- ty: Index,
- len: usize,
-) Allocator.Error!Index {
- try ip.items.ensureUnusedCapacity(gpa, 1);
- try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
-
- const str: String = @enumFromInt(ip.string_bytes.items.len - len);
- const adapter: KeyAdapter = .{ .intern_pool = ip };
- const gop = try ip.map.getOrPutAdapted(gpa, Key{ .aggregate = .{
- .ty = ty,
- .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(str)..] },
- } }, adapter);
- if (gop.found_existing) return @enumFromInt(gop.index);
-
- ip.items.appendAssumeCapacity(.{
- .tag = .bytes,
- .data = ip.addExtraAssumeCapacity(Bytes{
- .ty = ty,
- .bytes = str,
- }),
- });
- return @enumFromInt(ip.items.len - 1);
-}
-
pub fn getString(ip: *InternPool, s: []const u8) OptionalNullTerminatedString {
- if (ip.string_table.getKeyAdapted(s, std.hash_map.StringIndexAdapter{
+ return if (ip.string_table.getKeyAdapted(s, std.hash_map.StringIndexAdapter{
.bytes = &ip.string_bytes,
- })) |index| {
- return @as(NullTerminatedString, @enumFromInt(index)).toOptional();
- } else {
- return .none;
- }
-}
-
-pub fn stringToSlice(ip: *const InternPool, s: NullTerminatedString) [:0]const u8 {
- const string_bytes = ip.string_bytes.items;
- const start = @intFromEnum(s);
- var end: usize = start;
- while (string_bytes[end] != 0) end += 1;
- return string_bytes[start..end :0];
-}
-
-pub fn stringToSliceUnwrap(ip: *const InternPool, s: OptionalNullTerminatedString) ?[:0]const u8 {
- return ip.stringToSlice(s.unwrap() orelse return null);
-}
-
-pub fn stringEqlSlice(ip: *const InternPool, a: NullTerminatedString, b: []const u8) bool {
- return std.mem.eql(u8, stringToSlice(ip, a), b);
+ })) |index| @enumFromInt(index) else .none;
}
pub fn typeOf(ip: *const InternPool, index: Index) Index {
@@ -8767,7 +8793,7 @@ pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
return switch (ip.indexToKey(ty)) {
.struct_type => ip.loadStructType(ty).field_types.len,
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
- .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
+ .array_type => |array_type| array_type.lenIncludingSentinel(),
.vector_type => |vector_type| vector_type.len,
else => unreachable,
};
diff --git a/src/Module.zig b/src/Module.zig
index 0399a2f85b..c4d7f43fe4 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -763,11 +763,11 @@ pub const Namespace = struct {
) !InternPool.NullTerminatedString {
const ip = &zcu.intern_pool;
const count = count: {
- var count: usize = ip.stringToSlice(name).len + 1;
+ var count: usize = name.length(ip) + 1;
var cur_ns = &ns;
while (true) {
const decl = zcu.declPtr(cur_ns.decl_index);
- count += ip.stringToSlice(decl.name).len + 1;
+ count += decl.name.length(ip) + 1;
cur_ns = zcu.namespacePtr(cur_ns.parent.unwrap() orelse {
count += ns.file_scope.sub_file_path.len;
break :count count;
@@ -793,7 +793,7 @@ pub const Namespace = struct {
};
}
- return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start);
+ return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start, .no_embedded_nulls);
}
pub fn getType(ns: Namespace, zcu: *Zcu) Type {
@@ -980,17 +980,13 @@ pub const File = struct {
const ip = &mod.intern_pool;
const start = ip.string_bytes.items.len;
try file.renderFullyQualifiedName(ip.string_bytes.writer(mod.gpa));
- return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start);
+ return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start, .no_embedded_nulls);
}
pub fn fullPath(file: File, ally: Allocator) ![]u8 {
return file.mod.root.joinString(ally, file.sub_file_path);
}
- pub fn fullPathZ(file: File, ally: Allocator) ![:0]u8 {
- return file.mod.root.joinStringZ(ally, file.sub_file_path);
- }
-
pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
const loc = std.zig.findLineColumn(file.source.bytes, src);
std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
@@ -2534,6 +2530,7 @@ fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
const name_ip = try zcu.intern_pool.getOrPutString(
zcu.gpa,
old_zir.nullTerminatedString(name_zir),
+ .no_embedded_nulls,
);
try old_names.put(zcu.gpa, name_ip, {});
}
@@ -2551,6 +2548,7 @@ fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
const name_ip = try zcu.intern_pool.getOrPutString(
zcu.gpa,
old_zir.nullTerminatedString(name_zir),
+ .no_embedded_nulls,
);
if (!old_names.swapRemove(name_ip)) continue;
// Name added
@@ -3555,37 +3553,46 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
const gpa = mod.gpa;
const zir = decl.getFileScope(mod).zir;
- const builtin_type_target_index: InternPool.Index = blk: {
+ const builtin_type_target_index: InternPool.Index = ip_index: {
const std_mod = mod.std_mod;
- if (decl.getFileScope(mod).mod != std_mod) break :blk .none;
+ if (decl.getFileScope(mod).mod != std_mod) break :ip_index .none;
// We're in the std module.
const std_file = (try mod.importPkg(std_mod)).file;
const std_decl = mod.declPtr(std_file.root_decl.unwrap().?);
const std_namespace = std_decl.getInnerNamespace(mod).?;
- const builtin_str = try ip.getOrPutString(gpa, "builtin");
- const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .zcu = mod }) orelse break :blk .none);
- const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :blk .none;
- if (decl.src_namespace != builtin_namespace) break :blk .none;
+ const builtin_str = try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls);
+ const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .zcu = mod }) orelse break :ip_index .none);
+ const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :ip_index .none;
+ if (decl.src_namespace != builtin_namespace) break :ip_index .none;
// We're in builtin.zig. This could be a builtin we need to add to a specific InternPool index.
- for ([_]struct { []const u8, InternPool.Index }{
- .{ "AtomicOrder", .atomic_order_type },
- .{ "AtomicRmwOp", .atomic_rmw_op_type },
- .{ "CallingConvention", .calling_convention_type },
- .{ "AddressSpace", .address_space_type },
- .{ "FloatMode", .float_mode_type },
- .{ "ReduceOp", .reduce_op_type },
- .{ "CallModifier", .call_modifier_type },
- .{ "PrefetchOptions", .prefetch_options_type },
- .{ "ExportOptions", .export_options_type },
- .{ "ExternOptions", .extern_options_type },
- .{ "Type", .type_info_type },
- }) |pair| {
- const decl_name = ip.stringToSlice(decl.name);
- if (std.mem.eql(u8, decl_name, pair[0])) {
- break :blk pair[1];
- }
+ for ([_][]const u8{
+ "AtomicOrder",
+ "AtomicRmwOp",
+ "CallingConvention",
+ "AddressSpace",
+ "FloatMode",
+ "ReduceOp",
+ "CallModifier",
+ "PrefetchOptions",
+ "ExportOptions",
+ "ExternOptions",
+ "Type",
+ }, [_]InternPool.Index{
+ .atomic_order_type,
+ .atomic_rmw_op_type,
+ .calling_convention_type,
+ .address_space_type,
+ .float_mode_type,
+ .reduce_op_type,
+ .call_modifier_type,
+ .prefetch_options_type,
+ .export_options_type,
+ .extern_options_type,
+ .type_info_type,
+ }) |type_name, type_ip| {
+ if (decl.name.eqlSlice(type_name, ip)) break :ip_index type_ip;
}
- break :blk .none;
+ break :ip_index .none;
};
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
@@ -3725,8 +3732,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
} else if (bytes.len == 0) {
return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
}
- const section = try ip.getOrPutString(gpa, bytes);
- break :blk section.toOptional();
+ break :blk try ip.getOrPutStringOpt(gpa, bytes, .no_embedded_nulls);
};
decl.@"addrspace" = blk: {
const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) {
@@ -4101,7 +4107,10 @@ fn newEmbedFile(
.sentinel = .zero_u8,
.child = .u8_type,
} });
- const array_val = try ip.getTrailingAggregate(gpa, array_ty, bytes.len);
+ const array_val = try ip.get(gpa, .{ .aggregate = .{
+ .ty = array_ty,
+ .storage = .{ .bytes = try ip.getOrPutTrailingString(gpa, bytes.len, .maybe_embedded_nulls) },
+ } });
const ptr_ty = (try mod.ptrType(.{
.child = array_ty,
@@ -4111,7 +4120,6 @@ fn newEmbedFile(
.address_space = .generic,
},
})).toIntern();
-
const ptr_val = try ip.get(gpa, .{ .ptr = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
@@ -4122,7 +4130,7 @@ fn newEmbedFile(
result.* = new_file;
new_file.* = .{
- .sub_file_path = try ip.getOrPutString(gpa, sub_file_path),
+ .sub_file_path = try ip.getOrPutString(gpa, sub_file_path, .no_embedded_nulls),
.owner = pkg,
.stat = stat,
.val = ptr_val,
@@ -4214,11 +4222,11 @@ const ScanDeclIter = struct {
const zcu = iter.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
- var name = try ip.getOrPutStringFmt(gpa, fmt, args);
+ var name = try ip.getOrPutStringFmt(gpa, fmt, args, .no_embedded_nulls);
var gop = try iter.seen_decls.getOrPut(gpa, name);
var next_suffix: u32 = 0;
while (gop.found_existing) {
- name = try ip.getOrPutStringFmt(gpa, fmt ++ "_{d}", args ++ .{next_suffix});
+ name = try ip.getOrPutStringFmt(gpa, "{}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
gop = try iter.seen_decls.getOrPut(gpa, name);
next_suffix += 1;
}
@@ -4300,7 +4308,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
};
} else info: {
if (iter.pass != .named) return;
- const name = try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?));
+ const name = try ip.getOrPutString(
+ gpa,
+ zir.nullTerminatedString(declaration.name.toString(zir).?),
+ .no_embedded_nulls,
+ );
try iter.seen_decls.putNoClobber(gpa, name, {});
break :info .{
name,
@@ -4362,9 +4374,10 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
if (!comp.config.is_test) break :a false;
if (decl_mod != zcu.main_mod) break :a false;
if (is_named_test and comp.test_filters.len > 0) {
- const decl_fqn = ip.stringToSlice(try namespace.fullyQualifiedName(zcu, decl_name));
+ const decl_fqn = try namespace.fullyQualifiedName(zcu, decl_name);
+ const decl_fqn_slice = decl_fqn.toSlice(ip);
for (comp.test_filters) |test_filter| {
- if (mem.indexOf(u8, decl_fqn, test_filter)) |_| break;
+ if (mem.indexOf(u8, decl_fqn_slice, test_filter)) |_| break;
} else break :a false;
}
zcu.test_functions.putAssumeCapacity(decl_index, {}); // may clobber on incremental update
@@ -4377,8 +4390,8 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
// `is_export` is unchanged. In this case, the incremental update mechanism will handle
// re-analysis for us if necessary.
if (prev_exported != declaration.flags.is_export or decl.analysis == .unreferenced) {
- log.debug("scanDecl queue analyze_decl file='{s}' decl_name='{s}' decl_index={d}", .{
- namespace.file_scope.sub_file_path, ip.stringToSlice(decl_name), decl_index,
+ log.debug("scanDecl queue analyze_decl file='{s}' decl_name='{}' decl_index={d}", .{
+ namespace.file_scope.sub_file_path, decl_name.fmt(ip), decl_index,
});
comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = decl_index });
}
@@ -5300,7 +5313,7 @@ pub fn populateTestFunctions(
const builtin_file = (mod.importPkg(builtin_mod) catch unreachable).file;
const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?);
const builtin_namespace = mod.namespacePtr(root_decl.src_namespace);
- const test_functions_str = try ip.getOrPutString(gpa, "test_functions");
+ const test_functions_str = try ip.getOrPutString(gpa, "test_functions", .no_embedded_nulls);
const decl_index = builtin_namespace.decls.getKeyAdapted(
test_functions_str,
DeclAdapter{ .zcu = mod },
@@ -5327,16 +5340,16 @@ pub fn populateTestFunctions(
for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| {
const test_decl = mod.declPtr(test_decl_index);
- const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(try test_decl.fullyQualifiedName(mod)));
- defer gpa.free(test_decl_name);
+ const test_decl_name = try test_decl.fullyQualifiedName(mod);
+ const test_decl_name_len = test_decl_name.length(ip);
const test_name_anon_decl: InternPool.Key.Ptr.Addr.AnonDecl = n: {
const test_name_ty = try mod.arrayType(.{
- .len = test_decl_name.len,
+ .len = test_decl_name_len,
.child = .u8_type,
});
const test_name_val = try mod.intern(.{ .aggregate = .{
.ty = test_name_ty.toIntern(),
- .storage = .{ .bytes = test_decl_name },
+ .storage = .{ .bytes = test_decl_name.toString() },
} });
break :n .{
.orig_ty = (try mod.singleConstPtrType(test_name_ty)).toIntern(),
@@ -5354,7 +5367,7 @@ pub fn populateTestFunctions(
} }),
.len = try mod.intern(.{ .int = .{
.ty = .usize_type,
- .storage = .{ .u64 = test_decl_name.len },
+ .storage = .{ .u64 = test_decl_name_len },
} }),
} }),
// func
diff --git a/src/Package.zig b/src/Package.zig
index e173665e11..61f90727f3 100644
--- a/src/Package.zig
+++ b/src/Package.zig
@@ -2,3 +2,7 @@ pub const Module = @import("Package/Module.zig");
pub const Fetch = @import("Package/Fetch.zig");
pub const build_zig_basename = "build.zig";
pub const Manifest = @import("Package/Manifest.zig");
+
+test {
+ _ = Fetch;
+}
diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig
index 9aeaaffea3..506075e921 100644
--- a/src/Package/Fetch.zig
+++ b/src/Package/Fetch.zig
@@ -339,12 +339,12 @@ pub fn run(f: *Fetch) RunError!void {
.path_or_url => |path_or_url| {
if (fs.cwd().openDir(path_or_url, .{ .iterate = true })) |dir| {
var resource: Resource = .{ .dir = dir };
- return runResource(f, path_or_url, &resource, null);
+ return f.runResource(path_or_url, &resource, null);
} else |dir_err| {
const file_err = if (dir_err == error.NotDir) e: {
if (fs.cwd().openFile(path_or_url, .{})) |file| {
var resource: Resource = .{ .file = file };
- return runResource(f, path_or_url, &resource, null);
+ return f.runResource(path_or_url, &resource, null);
} else |err| break :e err;
} else dir_err;
@@ -356,7 +356,7 @@ pub fn run(f: *Fetch) RunError!void {
};
var server_header_buffer: [header_buffer_size]u8 = undefined;
var resource = try f.initResource(uri, &server_header_buffer);
- return runResource(f, uri.path, &resource, null);
+ return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, null);
}
},
};
@@ -418,7 +418,7 @@ pub fn run(f: *Fetch) RunError!void {
);
var server_header_buffer: [header_buffer_size]u8 = undefined;
var resource = try f.initResource(uri, &server_header_buffer);
- return runResource(f, uri.path, &resource, remote.hash);
+ return f.runResource(try uri.path.toRawMaybeAlloc(arena), &resource, remote.hash);
}
pub fn deinit(f: *Fetch) void {
@@ -461,14 +461,10 @@ fn runResource(
};
defer tmp_directory.handle.close();
- // Unpack resource into tmp_directory. A non-null return value means
- // that the package contents are inside a `pkg_dir` sub-directory.
- const pkg_dir = try unpackResource(f, resource, uri_path, tmp_directory);
+ // Fetch and unpack a resource into a temporary directory.
+ var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);
- var pkg_path: Cache.Path = .{
- .root_dir = tmp_directory,
- .sub_path = if (pkg_dir) |pkg_dir_name| pkg_dir_name else "",
- };
+ var pkg_path: Cache.Path = .{ .root_dir = tmp_directory, .sub_path = unpack_result.root_dir };
// Apply btrfs workaround if needed. Reopen tmp_directory.
if (native_os == .linux and f.job_queue.work_around_btrfs_bug) {
@@ -488,10 +484,9 @@ fn runResource(
.include_paths = if (f.manifest) |m| m.paths else .{},
};
- // TODO:
- // If any error occurred for files that were ultimately excluded, those
- // errors should be ignored, such as failure to create symlinks that
- // weren't supposed to be included anyway.
+ // Ignore errors that were excluded by manifest, such as failure to
+ // create symlinks that weren't supposed to be included anyway.
+ try unpack_result.validate(f, filter);
// Apply the manifest's inclusion rules to the temporary directory by
// deleting excluded files.
@@ -500,8 +495,8 @@ fn runResource(
// directory.
f.actual_hash = try computeHash(f, pkg_path, filter);
- break :blk if (pkg_dir) |pkg_dir_name|
- try fs.path.join(arena, &.{ tmp_dir_sub_path, pkg_dir_name })
+ break :blk if (unpack_result.root_dir.len > 0)
+ try fs.path.join(arena, &.{ tmp_dir_sub_path, unpack_result.root_dir })
else
tmp_dir_sub_path;
};
@@ -902,13 +897,14 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
const arena = f.arena.allocator();
const eb = &f.error_bundle;
- if (ascii.eqlIgnoreCase(uri.scheme, "file")) return .{
- .file = f.parent_package_root.openFile(uri.path, .{}) catch |err| {
+ if (ascii.eqlIgnoreCase(uri.scheme, "file")) {
+ const path = try uri.path.toRawMaybeAlloc(arena);
+ return .{ .file = f.parent_package_root.openFile(path, .{}) catch |err| {
return f.fail(f.location_tok, try eb.printString("unable to open '{}{s}': {s}", .{
- f.parent_package_root, uri.path, @errorName(err),
+ f.parent_package_root, path, @errorName(err),
}));
- },
- };
+ } };
+ }
const http_client = f.job_queue.http_client;
@@ -925,7 +921,7 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
};
errdefer req.deinit(); // releases more than memory
- req.send(.{}) catch |err| {
+ req.send() catch |err| {
return f.fail(f.location_tok, try eb.printString(
"HTTP request failed: {s}",
.{@errorName(err)},
@@ -972,7 +968,8 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
};
const want_oid = want_oid: {
- const want_ref = uri.fragment orelse "HEAD";
+ const want_ref =
+ if (uri.fragment) |fragment| try fragment.toRawMaybeAlloc(arena) else "HEAD";
if (git.parseOid(want_ref)) |oid| break :want_oid oid else |_| {}
const want_ref_head = try std.fmt.allocPrint(arena, "refs/heads/{s}", .{want_ref});
@@ -1044,16 +1041,12 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
));
}
-/// A `null` return value indicates the `tmp_directory` is populated directly
-/// with the package contents.
-/// A non-null return value means that the package contents are inside a
-/// sub-directory indicated by the named path.
fn unpackResource(
f: *Fetch,
resource: *Resource,
uri_path: []const u8,
tmp_directory: Cache.Directory,
-) RunError!?[]const u8 {
+) RunError!UnpackResult {
const eb = &f.error_bundle;
const file_type = switch (resource.*) {
.file => FileType.fromPath(uri_path) orelse
@@ -1121,7 +1114,7 @@ fn unpackResource(
.{ uri_path, @errorName(err) },
));
};
- return null;
+ return .{};
},
};
@@ -1156,27 +1149,22 @@ fn unpackResource(
});
return try unpackTarball(f, tmp_directory.handle, dcp.reader());
},
- .git_pack => {
- unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) {
- error.FetchFailed => return error.FetchFailed,
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| return f.fail(f.location_tok, try eb.printString(
- "unable to unpack git files: {s}",
- .{@errorName(e)},
- )),
- };
- return null;
+ .git_pack => return unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) {
+ error.FetchFailed => return error.FetchFailed,
+ error.OutOfMemory => return error.OutOfMemory,
+ else => |e| return f.fail(f.location_tok, try eb.printString(
+ "unable to unpack git files: {s}",
+ .{@errorName(e)},
+ )),
},
}
}
-fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const u8 {
+fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
const eb = &f.error_bundle;
const arena = f.arena.allocator();
- const gpa = f.arena.child_allocator;
- var diagnostics: std.tar.Diagnostics = .{ .allocator = gpa };
- defer diagnostics.deinit();
+ var diagnostics: std.tar.Diagnostics = .{ .allocator = arena };
std.tar.pipeToFileSystem(out_dir, reader, .{
.diagnostics = &diagnostics,
@@ -1188,53 +1176,27 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
.{@errorName(err)},
));
+ var res: UnpackResult = .{ .root_dir = diagnostics.root_dir };
if (diagnostics.errors.items.len > 0) {
- const notes_len: u32 = @intCast(diagnostics.errors.items.len);
- try eb.addRootErrorMessage(.{
- .msg = try eb.addString("unable to unpack tarball"),
- .src_loc = try f.srcLoc(f.location_tok),
- .notes_len = notes_len,
- });
- const notes_start = try eb.reserveNotes(notes_len);
- for (diagnostics.errors.items, notes_start..) |item, note_i| {
+ try res.allocErrors(arena, diagnostics.errors.items.len, "unable to unpack tarball");
+ for (diagnostics.errors.items) |item| {
switch (item) {
- .unable_to_create_sym_link => |info| {
- eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
- .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
- info.file_name, info.link_name, @errorName(info.code),
- }),
- }));
- },
- .unable_to_create_file => |info| {
- eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
- .msg = try eb.printString("unable to create file '{s}': {s}", .{
- info.file_name, @errorName(info.code),
- }),
- }));
- },
- .unsupported_file_type => |info| {
- eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
- .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{
- info.file_name, @intFromEnum(info.file_type),
- }),
- }));
- },
+ .unable_to_create_file => |i| res.unableToCreateFile(stripRoot(i.file_name, res.root_dir), i.code),
+ .unable_to_create_sym_link => |i| res.unableToCreateSymLink(stripRoot(i.file_name, res.root_dir), i.link_name, i.code),
+ .unsupported_file_type => |i| res.unsupportedFileType(stripRoot(i.file_name, res.root_dir), @intFromEnum(i.file_type)),
}
}
- return error.FetchFailed;
}
-
- return if (diagnostics.root_dir) |root_dir|
- return try arena.dupe(u8, root_dir)
- else
- null;
+ return res;
}
-fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void {
- const eb = &f.error_bundle;
+fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!UnpackResult {
+ const arena = f.arena.allocator();
const gpa = f.arena.child_allocator;
const want_oid = resource.git.want_oid;
const reader = resource.git.fetch_stream.reader();
+
+ var res: UnpackResult = .{};
// The .git directory is used to store the packfile and associated index, but
// we do not attempt to replicate the exact structure of a real .git
// directory, since that isn't relevant for fetching a package.
@@ -1265,35 +1227,23 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void
checkout_prog_node.activate();
var repository = try git.Repository.init(gpa, pack_file, index_file);
defer repository.deinit();
- var diagnostics: git.Diagnostics = .{ .allocator = gpa };
- defer diagnostics.deinit();
+ var diagnostics: git.Diagnostics = .{ .allocator = arena };
try repository.checkout(out_dir, want_oid, &diagnostics);
if (diagnostics.errors.items.len > 0) {
- const notes_len: u32 = @intCast(diagnostics.errors.items.len);
- try eb.addRootErrorMessage(.{
- .msg = try eb.addString("unable to unpack packfile"),
- .src_loc = try f.srcLoc(f.location_tok),
- .notes_len = notes_len,
- });
- const notes_start = try eb.reserveNotes(notes_len);
- for (diagnostics.errors.items, notes_start..) |item, note_i| {
+ try res.allocErrors(arena, diagnostics.errors.items.len, "unable to unpack packfile");
+ for (diagnostics.errors.items) |item| {
switch (item) {
- .unable_to_create_sym_link => |info| {
- eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
- .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
- info.file_name, info.link_name, @errorName(info.code),
- }),
- }));
- },
+ .unable_to_create_file => |i| res.unableToCreateFile(i.file_name, i.code),
+ .unable_to_create_sym_link => |i| res.unableToCreateSymLink(i.file_name, i.link_name, i.code),
}
}
- return error.InvalidGitPack;
}
}
}
try out_dir.deleteTree(".git");
+ return res;
}
fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void {
@@ -1743,6 +1693,7 @@ const native_os = builtin.os.tag;
test {
_ = Filter;
_ = FileType;
+ _ = UnpackResult;
}
// Detects executable header: ELF magic header or shebang line.
@@ -1778,3 +1729,469 @@ test FileHeader {
h.update(FileHeader.elf_magic[2..4]);
try std.testing.expect(h.isExecutable());
}
+
+// Result of the `unpackResource` operation. Enables collecting errors from
+// tar/git diagnostic, filtering that errors by manifest inclusion rules and
+// emitting remaining errors to an `ErrorBundle`.
+const UnpackResult = struct {
+ errors: []Error = undefined,
+ errors_count: usize = 0,
+ root_error_message: []const u8 = "",
+
+ // A non empty value means that the package contents are inside a
+ // sub-directory indicated by the named path.
+ root_dir: []const u8 = "",
+
+ const Error = union(enum) {
+ unable_to_create_sym_link: struct {
+ code: anyerror,
+ file_name: []const u8,
+ link_name: []const u8,
+ },
+ unable_to_create_file: struct {
+ code: anyerror,
+ file_name: []const u8,
+ },
+ unsupported_file_type: struct {
+ file_name: []const u8,
+ file_type: u8,
+ },
+
+ fn excluded(self: Error, filter: Filter) bool {
+ const file_name = switch (self) {
+ .unable_to_create_file => |info| info.file_name,
+ .unable_to_create_sym_link => |info| info.file_name,
+ .unsupported_file_type => |info| info.file_name,
+ };
+ return !filter.includePath(file_name);
+ }
+ };
+
+ fn allocErrors(self: *UnpackResult, arena: std.mem.Allocator, n: usize, root_error_message: []const u8) !void {
+ self.root_error_message = try arena.dupe(u8, root_error_message);
+ self.errors = try arena.alloc(UnpackResult.Error, n);
+ }
+
+ fn hasErrors(self: *UnpackResult) bool {
+ return self.errors_count > 0;
+ }
+
+ fn unableToCreateFile(self: *UnpackResult, file_name: []const u8, err: anyerror) void {
+ self.errors[self.errors_count] = .{ .unable_to_create_file = .{
+ .code = err,
+ .file_name = file_name,
+ } };
+ self.errors_count += 1;
+ }
+
+ fn unableToCreateSymLink(self: *UnpackResult, file_name: []const u8, link_name: []const u8, err: anyerror) void {
+ self.errors[self.errors_count] = .{ .unable_to_create_sym_link = .{
+ .code = err,
+ .file_name = file_name,
+ .link_name = link_name,
+ } };
+ self.errors_count += 1;
+ }
+
+ fn unsupportedFileType(self: *UnpackResult, file_name: []const u8, file_type: u8) void {
+ self.errors[self.errors_count] = .{ .unsupported_file_type = .{
+ .file_name = file_name,
+ .file_type = file_type,
+ } };
+ self.errors_count += 1;
+ }
+
+ fn validate(self: *UnpackResult, f: *Fetch, filter: Filter) !void {
+ if (self.errors_count == 0) return;
+
+ var unfiltered_errors: u32 = 0;
+ for (self.errors) |item| {
+ if (item.excluded(filter)) continue;
+ unfiltered_errors += 1;
+ }
+ if (unfiltered_errors == 0) return;
+
+ // Emmit errors to an `ErrorBundle`.
+ const eb = &f.error_bundle;
+ try eb.addRootErrorMessage(.{
+ .msg = try eb.addString(self.root_error_message),
+ .src_loc = try f.srcLoc(f.location_tok),
+ .notes_len = unfiltered_errors,
+ });
+ var note_i: u32 = try eb.reserveNotes(unfiltered_errors);
+ for (self.errors) |item| {
+ if (item.excluded(filter)) continue;
+ switch (item) {
+ .unable_to_create_sym_link => |info| {
+ eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
+ .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
+ info.file_name, info.link_name, @errorName(info.code),
+ }),
+ }));
+ },
+ .unable_to_create_file => |info| {
+ eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
+ .msg = try eb.printString("unable to create file '{s}': {s}", .{
+ info.file_name, @errorName(info.code),
+ }),
+ }));
+ },
+ .unsupported_file_type => |info| {
+ eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
+ .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{
+ info.file_name, info.file_type,
+ }),
+ }));
+ },
+ }
+ note_i += 1;
+ }
+
+ return error.FetchFailed;
+ }
+
+ test validate {
+ const gpa = std.testing.allocator;
+ var arena_instance = std.heap.ArenaAllocator.init(gpa);
+ defer arena_instance.deinit();
+ const arena = arena_instance.allocator();
+
+ // fill UnpackResult with errors
+ var res: UnpackResult = .{};
+ try res.allocErrors(arena, 4, "unable to unpack");
+ try std.testing.expectEqual(0, res.errors_count);
+ res.unableToCreateFile("dir1/file1", error.File1);
+ res.unableToCreateSymLink("dir2/file2", "filename", error.SymlinkError);
+ res.unableToCreateFile("dir1/file3", error.File3);
+ res.unsupportedFileType("dir2/file4", 'x');
+ try std.testing.expectEqual(4, res.errors_count);
+
+ // create filter, includes dir2, excludes dir1
+ var filter: Filter = .{};
+ try filter.include_paths.put(arena, "dir2", {});
+
+ // init Fetch
+ var fetch: Fetch = undefined;
+ fetch.parent_manifest_ast = null;
+ fetch.location_tok = 0;
+ try fetch.error_bundle.init(gpa);
+ defer fetch.error_bundle.deinit();
+
+ // validate errors with filter
+ try std.testing.expectError(error.FetchFailed, res.validate(&fetch, filter));
+
+ // output errors to string
+ var errors = try fetch.error_bundle.toOwnedBundle("");
+ defer errors.deinit(gpa);
+ var out = std.ArrayList(u8).init(gpa);
+ defer out.deinit();
+ try errors.renderToWriter(.{ .ttyconf = .no_color }, out.writer());
+ try std.testing.expectEqualStrings(
+ \\error: unable to unpack
+ \\ note: unable to create symlink from 'dir2/file2' to 'filename': SymlinkError
+ \\ note: file 'dir2/file4' has unsupported type 'x'
+ \\
+ , out.items);
+ }
+};
+
+test "tarball with duplicate paths" {
+ // This tarball has duplicate path 'dir1/file1' to simulate case sensitve
+ // file system on any file sytstem.
+ //
+ // duplicate_paths/
+ // duplicate_paths/dir1/
+ // duplicate_paths/dir1/file1
+ // duplicate_paths/dir1/file1
+ // duplicate_paths/build.zig.zon
+ // duplicate_paths/src/
+ // duplicate_paths/src/main.zig
+ // duplicate_paths/src/root.zig
+ // duplicate_paths/build.zig
+ //
+
+ const gpa = std.testing.allocator;
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+
+ const tarball_name = "duplicate_paths.tar.gz";
+ try saveEmbedFile(tarball_name, tmp.dir);
+ const tarball_path = try std.fmt.allocPrint(gpa, "zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
+ defer gpa.free(tarball_path);
+
+ // Run tarball fetch, expect to fail
+ var fb: TestFetchBuilder = undefined;
+ var fetch = try fb.build(gpa, tmp.dir, tarball_path);
+ defer fb.deinit();
+ try std.testing.expectError(error.FetchFailed, fetch.run());
+
+ try fb.expectFetchErrors(1,
+ \\error: unable to unpack tarball
+ \\ note: unable to create file 'dir1/file1': PathAlreadyExists
+ \\
+ );
+}
+
+test "tarball with excluded duplicate paths" {
+ // Same as previous tarball but has build.zig.zon wich excludes 'dir1'.
+ //
+ // .paths = .{
+ // "build.zig",
+ // "build.zig.zon",
+ // "src",
+ // }
+ //
+
+ const gpa = std.testing.allocator;
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+
+ const tarball_name = "duplicate_paths_excluded.tar.gz";
+ try saveEmbedFile(tarball_name, tmp.dir);
+ const tarball_path = try std.fmt.allocPrint(gpa, "zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
+ defer gpa.free(tarball_path);
+
+ // Run tarball fetch, should succeed
+ var fb: TestFetchBuilder = undefined;
+ var fetch = try fb.build(gpa, tmp.dir, tarball_path);
+ defer fb.deinit();
+ try fetch.run();
+
+ const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash);
+ try std.testing.expectEqualStrings(
+ "12200bafe035cbb453dd717741b66e9f9d1e6c674069d06121dafa1b2e62eb6b22da",
+ &hex_digest,
+ );
+
+ const expected_files: []const []const u8 = &.{
+ "build.zig",
+ "build.zig.zon",
+ "src/main.zig",
+ "src/root.zig",
+ };
+ try fb.expectPackageFiles(expected_files);
+}
+
+test "tarball without root folder" {
+ // Tarball with root folder. Manifest excludes dir1 and dir2.
+ //
+ // build.zig
+ // build.zig.zon
+ // dir1/
+ // dir1/file2
+ // dir1/file1
+ // dir2/
+ // dir2/file2
+ // src/
+ // src/main.zig
+ //
+
+ const gpa = std.testing.allocator;
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+
+ const tarball_name = "no_root.tar.gz";
+ try saveEmbedFile(tarball_name, tmp.dir);
+ const tarball_path = try std.fmt.allocPrint(gpa, "zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
+ defer gpa.free(tarball_path);
+
+ // Run tarball fetch, should succeed
+ var fb: TestFetchBuilder = undefined;
+ var fetch = try fb.build(gpa, tmp.dir, tarball_path);
+ defer fb.deinit();
+ try fetch.run();
+
+ const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash);
+ try std.testing.expectEqualStrings(
+ "12209f939bfdcb8b501a61bb4a43124dfa1b2848adc60eec1e4624c560357562b793",
+ &hex_digest,
+ );
+
+ const expected_files: []const []const u8 = &.{
+ "build.zig",
+ "build.zig.zon",
+ "src/main.zig",
+ };
+ try fb.expectPackageFiles(expected_files);
+}
+
+test "set executable bit based on file content" {
+ if (!std.fs.has_executable_bit) return error.SkipZigTest;
+ const gpa = std.testing.allocator;
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+
+ const tarball_name = "executables.tar.gz";
+ try saveEmbedFile(tarball_name, tmp.dir);
+ const tarball_path = try std.fmt.allocPrint(gpa, "zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name });
+ defer gpa.free(tarball_path);
+
+ // $ tar -tvf executables.tar.gz
+ // drwxrwxr-x 0 executables/
+ // -rwxrwxr-x 170 executables/hello
+ // lrwxrwxrwx 0 executables/hello_ln -> hello
+ // -rw-rw-r-- 0 executables/file1
+ // -rw-rw-r-- 17 executables/script_with_shebang_without_exec_bit
+ // -rwxrwxr-x 7 executables/script_without_shebang
+ // -rwxrwxr-x 17 executables/script
+
+ var fb: TestFetchBuilder = undefined;
+ var fetch = try fb.build(gpa, tmp.dir, tarball_path);
+ defer fb.deinit();
+
+ try fetch.run();
+ try std.testing.expectEqualStrings(
+ "1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3",
+ &Manifest.hexDigest(fetch.actual_hash),
+ );
+
+ var out = try fb.packageDir();
+ defer out.close();
+ const S = std.posix.S;
+ // expect executable bit not set
+ try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0);
+ try std.testing.expect((try out.statFile("script_without_shebang")).mode & S.IXUSR == 0);
+ // expect executable bit set
+ try std.testing.expect((try out.statFile("hello")).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile("script")).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile("script_with_shebang_without_exec_bit")).mode & S.IXUSR != 0);
+ try std.testing.expect((try out.statFile("hello_ln")).mode & S.IXUSR != 0);
+
+ //
+ // $ ls -al zig-cache/tmp/OCz9ovUcstDjTC_U/zig-global-cache/p/1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3
+ // -rw-rw-r-- 1 0 Apr file1
+ // -rwxrwxr-x 1 170 Apr hello
+ // lrwxrwxrwx 1 5 Apr hello_ln -> hello
+ // -rwxrwxr-x 1 17 Apr script
+ // -rw-rw-r-- 1 7 Apr script_without_shebang
+ // -rwxrwxr-x 1 17 Apr script_with_shebang_without_exec_bit
+}
+
+fn saveEmbedFile(comptime tarball_name: []const u8, dir: fs.Dir) !void {
+ //const tarball_name = "duplicate_paths_excluded.tar.gz";
+ const tarball_content = @embedFile("Fetch/testdata/" ++ tarball_name);
+ var tmp_file = try dir.createFile(tarball_name, .{});
+ defer tmp_file.close();
+ try tmp_file.writeAll(tarball_content);
+}
+
+// Builds Fetch with required dependencies, clears dependencies on deinit().
+const TestFetchBuilder = struct {
+ thread_pool: ThreadPool,
+ http_client: std.http.Client,
+ global_cache_directory: Cache.Directory,
+ progress: std.Progress,
+ job_queue: Fetch.JobQueue,
+ fetch: Fetch,
+
+ fn build(
+ self: *TestFetchBuilder,
+ allocator: std.mem.Allocator,
+ cache_parent_dir: std.fs.Dir,
+ path_or_url: []const u8,
+ ) !*Fetch {
+ const cache_dir = try cache_parent_dir.makeOpenPath("zig-global-cache", .{});
+
+ try self.thread_pool.init(.{ .allocator = allocator });
+ self.http_client = .{ .allocator = allocator };
+ self.global_cache_directory = .{ .handle = cache_dir, .path = null };
+
+ self.progress = .{ .dont_print_on_dumb = true };
+
+ self.job_queue = .{
+ .http_client = &self.http_client,
+ .thread_pool = &self.thread_pool,
+ .global_cache = self.global_cache_directory,
+ .recursive = false,
+ .read_only = false,
+ .debug_hash = false,
+ .work_around_btrfs_bug = false,
+ };
+
+ self.fetch = .{
+ .arena = std.heap.ArenaAllocator.init(allocator),
+ .location = .{ .path_or_url = path_or_url },
+ .location_tok = 0,
+ .hash_tok = 0,
+ .name_tok = 0,
+ .lazy_status = .eager,
+ .parent_package_root = Cache.Path{ .root_dir = Cache.Directory{ .handle = cache_dir, .path = null } },
+ .parent_manifest_ast = null,
+ .prog_node = self.progress.start("Fetch", 0),
+ .job_queue = &self.job_queue,
+ .omit_missing_hash_error = true,
+ .allow_missing_paths_field = false,
+
+ .package_root = undefined,
+ .error_bundle = undefined,
+ .manifest = null,
+ .manifest_ast = undefined,
+ .actual_hash = undefined,
+ .has_build_zig = false,
+ .oom_flag = false,
+ .module = null,
+ };
+ return &self.fetch;
+ }
+
+ fn deinit(self: *TestFetchBuilder) void {
+ self.fetch.deinit();
+ self.job_queue.deinit();
+ self.fetch.prog_node.end();
+ self.global_cache_directory.handle.close();
+ self.http_client.deinit();
+ self.thread_pool.deinit();
+ }
+
+ fn packageDir(self: *TestFetchBuilder) !fs.Dir {
+ const root = self.fetch.package_root;
+ return try root.root_dir.handle.openDir(root.sub_path, .{ .iterate = true });
+ }
+
+ // Test helper, asserts thet package dir constains expected_files.
+ // expected_files must be sorted.
+ fn expectPackageFiles(self: *TestFetchBuilder, expected_files: []const []const u8) !void {
+ var package_dir = try self.packageDir();
+ defer package_dir.close();
+
+ var actual_files: std.ArrayListUnmanaged([]u8) = .{};
+ defer actual_files.deinit(std.testing.allocator);
+ defer for (actual_files.items) |file| std.testing.allocator.free(file);
+ var walker = try package_dir.walk(std.testing.allocator);
+ defer walker.deinit();
+ while (try walker.next()) |entry| {
+ if (entry.kind != .file) continue;
+ const path = try std.testing.allocator.dupe(u8, entry.path);
+ errdefer std.testing.allocator.free(path);
+ std.mem.replaceScalar(u8, path, std.fs.path.sep, '/');
+ try actual_files.append(std.testing.allocator, path);
+ }
+ std.mem.sortUnstable([]u8, actual_files.items, {}, struct {
+ fn lessThan(_: void, a: []u8, b: []u8) bool {
+ return std.mem.lessThan(u8, a, b);
+ }
+ }.lessThan);
+
+ try std.testing.expectEqual(expected_files.len, actual_files.items.len);
+ for (expected_files, 0..) |file_name, i| {
+ try std.testing.expectEqualStrings(file_name, actual_files.items[i]);
+ }
+ try std.testing.expectEqualDeep(expected_files, actual_files.items);
+ }
+
+ // Test helper, asserts that fetch has failed with `msg` error message.
+ fn expectFetchErrors(self: *TestFetchBuilder, notes_len: usize, msg: []const u8) !void {
+ var errors = try self.fetch.error_bundle.toOwnedBundle("");
+ defer errors.deinit(std.testing.allocator);
+
+ const em = errors.getErrorMessage(errors.getMessages()[0]);
+ try std.testing.expectEqual(1, em.count);
+ if (notes_len > 0) {
+ try std.testing.expectEqual(notes_len, em.notes_len);
+ }
+ var al = std.ArrayList(u8).init(std.testing.allocator);
+ defer al.deinit();
+ try errors.renderToWriter(.{ .ttyconf = .no_color }, al.writer());
+ try std.testing.expectEqualStrings(msg, al.items);
+ }
+};
diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig
index 36652bd88c..a8c106412e 100644
--- a/src/Package/Fetch/git.zig
+++ b/src/Package/Fetch/git.zig
@@ -46,6 +46,10 @@ pub const Diagnostics = struct {
file_name: []const u8,
link_name: []const u8,
},
+ unable_to_create_file: struct {
+ code: anyerror,
+ file_name: []const u8,
+ },
};
pub fn deinit(d: *Diagnostics) void {
@@ -55,6 +59,9 @@ pub const Diagnostics = struct {
d.allocator.free(info.file_name);
d.allocator.free(info.link_name);
},
+ .unable_to_create_file => |info| {
+ d.allocator.free(info.file_name);
+ },
}
}
d.errors.deinit(d.allocator);
@@ -119,11 +126,19 @@ pub const Repository = struct {
try repository.checkoutTree(subdir, entry.oid, sub_path, diagnostics);
},
.file => {
- var file = try dir.createFile(entry.name, .{});
- defer file.close();
try repository.odb.seekOid(entry.oid);
const file_object = try repository.odb.readObject();
if (file_object.type != .blob) return error.InvalidFile;
+ var file = dir.createFile(entry.name, .{ .exclusive = true }) catch |e| {
+ const file_name = try std.fs.path.join(diagnostics.allocator, &.{ current_path, entry.name });
+ errdefer diagnostics.allocator.free(file_name);
+ try diagnostics.errors.append(diagnostics.allocator, .{ .unable_to_create_file = .{
+ .code = e,
+ .file_name = file_name,
+ } });
+ continue;
+ };
+ defer file.close();
try file.writeAll(file_object.data);
try file.sync();
},
@@ -525,9 +540,13 @@ pub const Session = struct {
http_headers_buffer: []u8,
) !CapabilityIterator {
var info_refs_uri = session.uri;
- info_refs_uri.path = try std.fs.path.resolvePosix(allocator, &.{ "/", session.uri.path, "info/refs" });
- defer allocator.free(info_refs_uri.path);
- info_refs_uri.query = "service=git-upload-pack";
+ {
+ const session_uri_path = try std.fmt.allocPrint(allocator, "{path}", .{session.uri.path});
+ defer allocator.free(session_uri_path);
+ info_refs_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(allocator, &.{ "/", session_uri_path, "info/refs" }) };
+ }
+ defer allocator.free(info_refs_uri.path.percent_encoded);
+ info_refs_uri.query = .{ .percent_encoded = "service=git-upload-pack" };
info_refs_uri.fragment = null;
const max_redirects = 3;
@@ -539,16 +558,18 @@ pub const Session = struct {
},
});
errdefer request.deinit();
- try request.send(.{});
+ try request.send();
try request.finish();
try request.wait();
if (request.response.status != .ok) return error.ProtocolError;
const any_redirects_occurred = request.redirect_behavior.remaining() < max_redirects;
if (any_redirects_occurred) {
- if (!mem.endsWith(u8, request.uri.path, "/info/refs")) return error.UnparseableRedirect;
+ const request_uri_path = try std.fmt.allocPrint(allocator, "{path}", .{request.uri.path});
+ defer allocator.free(request_uri_path);
+ if (!mem.endsWith(u8, request_uri_path, "/info/refs")) return error.UnparseableRedirect;
var new_uri = request.uri;
- new_uri.path = new_uri.path[0 .. new_uri.path.len - "/info/refs".len];
+ new_uri.path = .{ .percent_encoded = request_uri_path[0 .. request_uri_path.len - "/info/refs".len] };
new_uri.query = null;
redirect_uri.* = try std.fmt.allocPrint(allocator, "{+/}", .{new_uri});
return error.Redirected;
@@ -630,8 +651,12 @@ pub const Session = struct {
/// Returns an iterator over refs known to the server.
pub fn listRefs(session: Session, allocator: Allocator, options: ListRefsOptions) !RefIterator {
var upload_pack_uri = session.uri;
- upload_pack_uri.path = try std.fs.path.resolvePosix(allocator, &.{ "/", session.uri.path, "git-upload-pack" });
- defer allocator.free(upload_pack_uri.path);
+ {
+ const session_uri_path = try std.fmt.allocPrint(allocator, "{path}", .{session.uri.path});
+ defer allocator.free(session_uri_path);
+ upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(allocator, &.{ "/", session_uri_path, "git-upload-pack" }) };
+ }
+ defer allocator.free(upload_pack_uri.path.percent_encoded);
upload_pack_uri.query = null;
upload_pack_uri.fragment = null;
@@ -666,7 +691,7 @@ pub const Session = struct {
});
errdefer request.deinit();
request.transfer_encoding = .{ .content_length = body.items.len };
- try request.send(.{});
+ try request.send();
try request.writeAll(body.items);
try request.finish();
@@ -733,8 +758,12 @@ pub const Session = struct {
http_headers_buffer: []u8,
) !FetchStream {
var upload_pack_uri = session.uri;
- upload_pack_uri.path = try std.fs.path.resolvePosix(allocator, &.{ "/", session.uri.path, "git-upload-pack" });
- defer allocator.free(upload_pack_uri.path);
+ {
+ const session_uri_path = try std.fmt.allocPrint(allocator, "{path}", .{session.uri.path});
+ defer allocator.free(session_uri_path);
+ upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(allocator, &.{ "/", session_uri_path, "git-upload-pack" }) };
+ }
+ defer allocator.free(upload_pack_uri.path.percent_encoded);
upload_pack_uri.query = null;
upload_pack_uri.fragment = null;
@@ -771,7 +800,7 @@ pub const Session = struct {
});
errdefer request.deinit();
request.transfer_encoding = .{ .content_length = body.items.len };
- try request.send(.{});
+ try request.send();
try request.writeAll(body.items);
try request.finish();
diff --git a/src/Package/Fetch/testdata/duplicate_paths.tar.gz b/src/Package/Fetch/testdata/duplicate_paths.tar.gz
new file mode 100644
index 0000000000..118a934c1b
--- /dev/null
+++ b/src/Package/Fetch/testdata/duplicate_paths.tar.gz
Binary files differ
diff --git a/src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gz b/src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gz
new file mode 100644
index 0000000000..760b37cd40
--- /dev/null
+++ b/src/Package/Fetch/testdata/duplicate_paths_excluded.tar.gz
Binary files differ
diff --git a/src/Package/Fetch/testdata/executables.tar.gz b/src/Package/Fetch/testdata/executables.tar.gz
new file mode 100644
index 0000000000..abc650801e
--- /dev/null
+++ b/src/Package/Fetch/testdata/executables.tar.gz
Binary files differ
diff --git a/src/Package/Fetch/testdata/no_root.tar.gz b/src/Package/Fetch/testdata/no_root.tar.gz
new file mode 100644
index 0000000000..a3a4baf40f
--- /dev/null
+++ b/src/Package/Fetch/testdata/no_root.tar.gz
Binary files differ
diff --git a/src/Sema.zig b/src/Sema.zig
index d64226fef0..d3989f630c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -2059,12 +2059,12 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty));
// st.instruction_addresses = &addrs;
- const instruction_addresses_field_name = try ip.getOrPutString(gpa, "instruction_addresses");
+ const instruction_addresses_field_name = try ip.getOrPutString(gpa, "instruction_addresses", .no_embedded_nulls);
const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, instruction_addresses_field_name, src, true);
try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
// st.index = 0;
- const index_field_name = try ip.getOrPutString(gpa, "index");
+ const index_field_name = try ip.getOrPutString(gpa, "index", .no_embedded_nulls);
const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, index_field_name, src, true);
try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
@@ -2348,13 +2348,13 @@ fn failWithInvalidFieldAccess(
fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: InternPool.NullTerminatedString) bool {
const ip = &mod.intern_pool;
switch (ty.zigTypeTag(mod)) {
- .Array => return ip.stringEqlSlice(field_name, "len"),
+ .Array => return field_name.eqlSlice("len", ip),
.Pointer => {
const ptr_info = ty.ptrInfo(mod);
if (ptr_info.flags.size == .Slice) {
- return ip.stringEqlSlice(field_name, "ptr") or ip.stringEqlSlice(field_name, "len");
+ return field_name.eqlSlice("ptr", ip) or field_name.eqlSlice("len", ip);
} else if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Array) {
- return ip.stringEqlSlice(field_name, "len");
+ return field_name.eqlSlice("len", ip);
} else return false;
},
.Type, .Struct, .Union => return true,
@@ -2703,12 +2703,20 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
}),
.decl_val => |str| capture: {
- const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl_name = try ip.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(str),
+ .no_embedded_nulls,
+ );
const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl });
},
.decl_ref => |str| capture: {
- const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl_name = try ip.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(str),
+ .no_embedded_nulls,
+ );
const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl });
},
@@ -2882,7 +2890,7 @@ fn createAnonymousDeclTypeNamed(
const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{
src_decl.name.fmt(&mod.intern_pool), anon_prefix, @intFromEnum(new_decl_index),
- }) catch unreachable;
+ }, .no_embedded_nulls) catch unreachable;
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
return new_decl_index;
},
@@ -2923,7 +2931,7 @@ fn createAnonymousDeclTypeNamed(
};
try writer.writeByte(')');
- const name = try mod.intern_pool.getOrPutString(gpa, buf.items);
+ const name = try mod.intern_pool.getOrPutString(gpa, buf.items, .no_embedded_nulls);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
return new_decl_index;
},
@@ -2937,8 +2945,7 @@ fn createAnonymousDeclTypeNamed(
const name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}.{s}", .{
src_decl.name.fmt(&mod.intern_pool), zir_data[i].str_op.getStr(sema.code),
- });
-
+ }, .no_embedded_nulls);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
return new_decl_index;
},
@@ -3157,7 +3164,7 @@ fn zirEnumDecl(
const field_name_zir = sema.code.nullTerminatedString(field_name_index);
extra_index += 2; // field name, doc comment
- const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
+ const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir, .no_embedded_nulls);
const tag_overflow = if (has_tag_value) overflow: {
const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
@@ -3462,7 +3469,7 @@ fn zirErrorSetDecl(
while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string
const name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
const name = sema.code.nullTerminatedString(name_index);
- const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
+ const name_ip = try mod.intern_pool.getOrPutString(gpa, name, .no_embedded_nulls);
_ = try mod.getErrorValue(name_ip);
const result = names.getOrPutAssumeCapacity(name_ip);
assert(!result.found_existing); // verified in AstGen
@@ -3635,7 +3642,7 @@ fn indexablePtrLen(
const is_pointer_to = object_ty.isSinglePointer(mod);
const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty;
try checkIndexable(sema, block, src, indexable_ty);
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len");
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len", .no_embedded_nulls);
return sema.fieldVal(block, src, object, field_name, src);
}
@@ -3649,7 +3656,7 @@ fn indexablePtrLenOrNone(
const operand_ty = sema.typeOf(operand);
try checkMemOperand(sema, block, src, operand_ty);
if (operand_ty.ptrSize(mod) == .Many) return .none;
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len");
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len", .no_embedded_nulls);
return sema.fieldVal(block, src, operand, field_name, src);
}
@@ -4363,7 +4370,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
if (!object_ty.indexableHasLen(mod)) continue;
- break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, "len"), arg_src);
+ break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, "len", .no_embedded_nulls), arg_src);
};
const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src);
if (len == .none) {
@@ -4747,7 +4754,11 @@ fn validateUnionInit(
const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
- const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start));
+ const field_name = try mod.intern_pool.getOrPutString(
+ gpa,
+ sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
+ .no_embedded_nulls,
+ );
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
const air_tags = sema.air_instructions.items(.tag);
const air_datas = sema.air_instructions.items(.data);
@@ -4890,6 +4901,7 @@ fn validateStructInit(
const field_name = try ip.getOrPutString(
gpa,
sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
+ .no_embedded_nulls,
);
field_index.* = if (struct_ty.isTuple(mod))
try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
@@ -5672,25 +5684,26 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const bytes = sema.code.instructions.items(.data)[@intFromEnum(inst)].str.get(sema.code);
- return sema.addStrLitNoAlias(bytes);
+ return sema.addStrLit(
+ try sema.mod.intern_pool.getOrPutString(sema.gpa, bytes, .maybe_embedded_nulls),
+ bytes.len,
+ );
}
-fn addStrLit(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
- const duped_bytes = try sema.arena.dupe(u8, bytes);
- return addStrLitNoAlias(sema, duped_bytes);
+fn addNullTerminatedStrLit(sema: *Sema, string: InternPool.NullTerminatedString) CompileError!Air.Inst.Ref {
+ return sema.addStrLit(string.toString(), string.length(&sema.mod.intern_pool));
}
-/// Safe to call when `bytes` does not point into `InternPool`.
-fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
+fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const array_ty = try mod.arrayType(.{
- .len = bytes.len,
+ .len = len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const val = try mod.intern(.{ .aggregate = .{
.ty = array_ty.toIntern(),
- .storage = .{ .bytes = bytes },
+ .storage = .{ .bytes = string },
} });
return anonDeclRef(sema, val);
}
@@ -6370,7 +6383,11 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
- const decl_name = try mod.intern_pool.getOrPutString(mod.gpa, sema.code.nullTerminatedString(extra.decl_name));
+ const decl_name = try mod.intern_pool.getOrPutString(
+ mod.gpa,
+ sema.code.nullTerminatedString(extra.decl_name),
+ .no_embedded_nulls,
+ );
const decl_index = if (extra.namespace != .none) index_blk: {
const container_ty = try sema.resolveType(block, operand_src, extra.namespace);
const container_namespace = container_ty.getNamespaceIndex(mod);
@@ -6721,7 +6738,11 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
const src = inst_data.src();
- const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ const decl_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ inst_data.get(sema.code),
+ .no_embedded_nulls,
+ );
const decl_index = try sema.lookupIdentifier(block, src, decl_name);
try sema.addReferencedBy(block, src, decl_index);
return sema.analyzeDeclRef(decl_index);
@@ -6731,7 +6752,11 @@ fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
const src = inst_data.src();
- const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ const decl_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ inst_data.get(sema.code),
+ .no_embedded_nulls,
+ );
const decl = try sema.lookupIdentifier(block, src, decl_name);
return sema.analyzeDeclVal(block, src, decl);
}
@@ -6883,7 +6908,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
else => |e| return e,
};
- const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, .unneeded) catch |err| switch (err) {
error.AnalysisFail, error.NeededSourceLocation => @panic("std.builtin.StackTrace is corrupt"),
error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
@@ -6926,7 +6951,7 @@ fn popErrorReturnTrace(
try sema.resolveTypeFields(stack_trace_ty);
const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
- const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true);
try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store);
} else if (is_non_error == null) {
@@ -6952,7 +6977,7 @@ fn popErrorReturnTrace(
try sema.resolveTypeFields(stack_trace_ty);
const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
- const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true);
try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store);
_ = try then_block.addBr(cond_block_inst, .void_value);
@@ -7010,7 +7035,11 @@ fn zirCall(
.direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
.field => blk: {
const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));
+ const field_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(extra.data.field_name_start),
+ .no_embedded_nulls,
+ );
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
},
@@ -7073,7 +7102,7 @@ fn zirCall(
if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) {
const stack_trace_ty = try sema.getBuiltinType("StackTrace");
try sema.resolveTypeFields(stack_trace_ty);
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index");
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index", .no_embedded_nulls);
const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
// Insert a save instruction before the arg resolution + call instructions we just generated
@@ -8648,7 +8677,11 @@ fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
_ = block;
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
- const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ const name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ inst_data.get(sema.code),
+ .no_embedded_nulls,
+ );
_ = try mod.getErrorValue(name);
// Create an error set type with only this error value, and return the value.
const error_set_type = try mod.singleErrorSetType(name);
@@ -8804,7 +8837,7 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
const name = inst_data.get(sema.code);
return Air.internedToRef((try mod.intern(.{
- .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name),
+ .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name, .no_embedded_nulls),
})));
}
@@ -9761,7 +9794,7 @@ fn funcCommon(
const func_index = try ip.getExternFunc(gpa, .{
.ty = func_ty,
.decl = sema.owner_decl_index,
- .lib_name = try mod.intern_pool.getOrPutStringOpt(gpa, opt_lib_name),
+ .lib_name = try mod.intern_pool.getOrPutStringOpt(gpa, opt_lib_name, .no_embedded_nulls),
});
return finishFunc(
sema,
@@ -10225,7 +10258,11 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
+ const field_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(extra.field_name_start),
+ .no_embedded_nulls,
+ );
const object = try sema.resolveInst(extra.lhs);
return sema.fieldVal(block, src, object, field_name, field_name_src);
}
@@ -10239,7 +10276,11 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
+ const field_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(extra.field_name_start),
+ .no_embedded_nulls,
+ );
const object_ptr = try sema.resolveInst(extra.lhs);
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
}
@@ -10253,7 +10294,11 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name_init = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
+ const field_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ sema.code.nullTerminatedString(extra.field_name_start),
+ .no_embedded_nulls,
+ );
const object_ptr = try sema.resolveInst(extra.lhs);
const struct_ty = sema.typeOf(object_ptr).childType(mod);
switch (struct_ty.zigTypeTag(mod)) {
@@ -13759,8 +13804,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
switch (ip.indexToKey(ty.toIntern())) {
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.Slice => {
- if (ip.stringEqlSlice(field_name, "ptr")) break :hf true;
- if (ip.stringEqlSlice(field_name, "len")) break :hf true;
+ if (field_name.eqlSlice("ptr", ip)) break :hf true;
+ if (field_name.eqlSlice("len", ip)) break :hf true;
break :hf false;
},
else => {},
@@ -13783,7 +13828,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.enum_type => {
break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
},
- .array_type => break :hf ip.stringEqlSlice(field_name, "len"),
+ .array_type => break :hf field_name.eqlSlice("len", ip),
else => {},
}
return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
@@ -13885,7 +13930,11 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
- const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ const name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ inst_data.get(sema.code),
+ .no_embedded_nulls,
+ );
_ = try mod.getErrorValue(name);
const error_set_type = try mod.singleErrorSetType(name);
return Air.internedToRef((try mod.intern(.{ .err = .{
@@ -17552,11 +17601,9 @@ fn zirBuiltinSrc(
const gpa = sema.gpa;
const func_name_val = v: {
- // This dupe prevents InternPool string pool memory from being reallocated
- // while a reference exists.
- const bytes = try sema.arena.dupe(u8, ip.stringToSlice(fn_owner_decl.name));
+ const func_name_len = fn_owner_decl.name.length(ip);
const array_ty = try ip.get(gpa, .{ .array_type = .{
- .len = bytes.len,
+ .len = func_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
} });
@@ -17568,19 +17615,19 @@ fn zirBuiltinSrc(
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
- .storage = .{ .bytes = bytes },
+ .storage = .{ .bytes = fn_owner_decl.name.toString() },
} }),
} },
} }),
- .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, func_name_len)).toIntern(),
} });
};
const file_name_val = v: {
// The compiler must not call realpath anywhere.
- const bytes = try fn_owner_decl.getFileScope(mod).fullPathZ(sema.arena);
+ const file_name = try fn_owner_decl.getFileScope(mod).fullPath(sema.arena);
const array_ty = try ip.get(gpa, .{ .array_type = .{
- .len = bytes.len,
+ .len = file_name.len,
.sentinel = .zero_u8,
.child = .u8_type,
} });
@@ -17592,11 +17639,13 @@ fn zirBuiltinSrc(
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
- .storage = .{ .bytes = bytes },
+ .storage = .{
+ .bytes = try ip.getOrPutString(gpa, file_name, .maybe_embedded_nulls),
+ },
} }),
} },
} }),
- .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, file_name.len)).toIntern(),
} });
};
@@ -17651,7 +17700,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Fn"),
+ try ip.getOrPutString(gpa, "Fn", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(fn_info_decl_index);
const fn_info_decl = mod.declPtr(fn_info_decl_index);
@@ -17661,7 +17710,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
fn_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Param"),
+ try ip.getOrPutString(gpa, "Param", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(param_info_decl_index);
const param_info_decl = mod.declPtr(param_info_decl_index);
@@ -17762,7 +17811,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Int"),
+ try ip.getOrPutString(gpa, "Int", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(int_info_decl_index);
const int_info_decl = mod.declPtr(int_info_decl_index);
@@ -17790,7 +17839,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Float"),
+ try ip.getOrPutString(gpa, "Float", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(float_info_decl_index);
const float_info_decl = mod.declPtr(float_info_decl_index);
@@ -17822,7 +17871,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
(try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Pointer"),
+ try ip.getOrPutString(gpa, "Pointer", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(decl_index);
const decl = mod.declPtr(decl_index);
@@ -17833,7 +17882,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
pointer_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Size"),
+ try ip.getOrPutString(gpa, "Size", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(decl_index);
const decl = mod.declPtr(decl_index);
@@ -17876,7 +17925,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Array"),
+ try ip.getOrPutString(gpa, "Array", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(array_field_ty_decl_index);
const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index);
@@ -17907,7 +17956,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Vector"),
+ try ip.getOrPutString(gpa, "Vector", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(vector_field_ty_decl_index);
const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index);
@@ -17936,7 +17985,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Optional"),
+ try ip.getOrPutString(gpa, "Optional", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(optional_field_ty_decl_index);
const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index);
@@ -17963,7 +18012,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Error"),
+ try ip.getOrPutString(gpa, "Error", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(set_field_ty_decl_index);
const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index);
@@ -17980,18 +18029,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
else => |err_set_ty_index| blk: {
const names = ip.indexToKey(err_set_ty_index).error_set_type.names;
const vals = try sema.arena.alloc(InternPool.Index, names.len);
- for (vals, 0..) |*field_val, i| {
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupeZ(u8, ip.stringToSlice(names.get(ip)[i]));
- const name_val = v: {
+ for (vals, 0..) |*field_val, error_index| {
+ const error_name = names.get(ip)[error_index];
+ const error_name_len = error_name.length(ip);
+ const error_name_val = v: {
const new_decl_ty = try mod.arrayType(.{
- .len = name.len,
+ .len = error_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = error_name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18002,13 +18051,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
- .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, error_name_len)).toIntern(),
} });
};
const error_field_fields = .{
// name: [:0]const u8,
- name_val,
+ error_name_val,
};
field_val.* = try mod.intern(.{ .aggregate = .{
.ty = error_field_ty.toIntern(),
@@ -18069,7 +18118,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "ErrorUnion"),
+ try ip.getOrPutString(gpa, "ErrorUnion", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index);
const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index);
@@ -18099,7 +18148,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "EnumField"),
+ try ip.getOrPutString(gpa, "EnumField", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(enum_field_ty_decl_index);
const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index);
@@ -18107,27 +18156,29 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
};
const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);
- for (enum_field_vals, 0..) |*field_val, i| {
+ for (enum_field_vals, 0..) |*field_val, tag_index| {
const enum_type = ip.loadEnumType(ty.toIntern());
const value_val = if (enum_type.values.len > 0)
try mod.intern_pool.getCoercedInts(
mod.gpa,
- mod.intern_pool.indexToKey(enum_type.values.get(ip)[i]).int,
+ mod.intern_pool.indexToKey(enum_type.values.get(ip)[tag_index]).int,
.comptime_int_type,
)
else
- (try mod.intValue(Type.comptime_int, i)).toIntern();
+ (try mod.intValue(Type.comptime_int, tag_index)).toIntern();
+
// TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupeZ(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
const name_val = v: {
+ const tag_name = enum_type.names.get(ip)[tag_index];
+ const tag_name_len = tag_name.length(ip);
const new_decl_ty = try mod.arrayType(.{
- .len = name.len,
+ .len = tag_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = tag_name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18138,7 +18189,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
- .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, tag_name_len)).toIntern(),
} });
};
@@ -18191,7 +18242,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Enum"),
+ try ip.getOrPutString(gpa, "Enum", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(type_enum_ty_decl_index);
const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index);
@@ -18223,7 +18274,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Union"),
+ try ip.getOrPutString(gpa, "Union", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(type_union_ty_decl_index);
const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index);
@@ -18235,7 +18286,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "UnionField"),
+ try ip.getOrPutString(gpa, "UnionField", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(union_field_ty_decl_index);
const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index);
@@ -18250,18 +18301,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len);
defer gpa.free(union_field_vals);
- for (union_field_vals, 0..) |*field_val, i| {
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupeZ(u8, ip.stringToSlice(tag_type.names.get(ip)[i]));
+ for (union_field_vals, 0..) |*field_val, field_index| {
const name_val = v: {
+ const field_name = tag_type.names.get(ip)[field_index];
+ const field_name_len = field_name.length(ip);
const new_decl_ty = try mod.arrayType(.{
- .len = name.len,
+ .len = field_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = field_name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18272,16 +18323,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
- .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
} });
};
const alignment = switch (layout) {
- .auto, .@"extern" => try sema.unionFieldAlignment(union_obj, @intCast(i)),
+ .auto, .@"extern" => try sema.unionFieldAlignment(union_obj, @intCast(field_index)),
.@"packed" => .none,
};
- const field_ty = union_obj.field_types.get(ip)[i];
+ const field_ty = union_obj.field_types.get(ip)[field_index];
const union_field_fields = .{
// name: [:0]const u8,
name_val,
@@ -18338,7 +18389,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
(try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "ContainerLayout"),
+ try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(decl_index);
const decl = mod.declPtr(decl_index);
@@ -18371,7 +18422,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Struct"),
+ try ip.getOrPutString(gpa, "Struct", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(type_struct_ty_decl_index);
const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index);
@@ -18383,7 +18434,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "StructField"),
+ try ip.getOrPutString(gpa, "StructField", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(struct_field_ty_decl_index);
const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index);
@@ -18396,27 +18447,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
defer gpa.free(struct_field_vals);
fv: {
const struct_type = switch (ip.indexToKey(ty.toIntern())) {
- .anon_struct_type => |tuple| {
- struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len);
- for (struct_field_vals, 0..) |*struct_field_val, i| {
- const anon_struct_type = ip.indexToKey(ty.toIntern()).anon_struct_type;
- const field_ty = anon_struct_type.types.get(ip)[i];
- const field_val = anon_struct_type.values.get(ip)[i];
+ .anon_struct_type => |anon_struct_type| {
+ struct_field_vals = try gpa.alloc(InternPool.Index, anon_struct_type.types.len);
+ for (struct_field_vals, 0..) |*struct_field_val, field_index| {
+ const field_ty = anon_struct_type.types.get(ip)[field_index];
+ const field_val = anon_struct_type.values.get(ip)[field_index];
const name_val = v: {
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const bytes = if (tuple.names.len != 0)
- // https://github.com/ziglang/zig/issues/15709
- try sema.arena.dupeZ(u8, ip.stringToSlice(ip.indexToKey(ty.toIntern()).anon_struct_type.names.get(ip)[i]))
+ const field_name = if (anon_struct_type.names.len != 0)
+ anon_struct_type.names.get(ip)[field_index]
else
- try std.fmt.allocPrintZ(sema.arena, "{d}", .{i});
+ try ip.getOrPutStringFmt(gpa, "{d}", .{field_index}, .no_embedded_nulls);
+ const field_name_len = field_name.length(ip);
const new_decl_ty = try mod.arrayType(.{
- .len = bytes.len,
+ .len = field_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = bytes },
+ .storage = .{ .bytes = field_name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18427,7 +18476,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
- .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
} });
};
@@ -18462,24 +18511,24 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.resolveStructFieldInits(ty);
- for (struct_field_vals, 0..) |*field_val, i| {
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const name = if (struct_type.fieldName(ip, i).unwrap()) |name_nts|
- try sema.arena.dupeZ(u8, ip.stringToSlice(name_nts))
+ for (struct_field_vals, 0..) |*field_val, field_index| {
+ const field_name = if (struct_type.fieldName(ip, field_index).unwrap()) |field_name|
+ field_name
else
- try std.fmt.allocPrintZ(sema.arena, "{d}", .{i});
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
- const field_init = struct_type.fieldInit(ip, i);
- const field_is_comptime = struct_type.fieldIsComptime(ip, i);
+ try ip.getOrPutStringFmt(gpa, "{d}", .{field_index}, .no_embedded_nulls);
+ const field_name_len = field_name.length(ip);
+ const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
+ const field_init = struct_type.fieldInit(ip, field_index);
+ const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);
const name_val = v: {
const new_decl_ty = try mod.arrayType(.{
- .len = name.len,
+ .len = field_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = field_name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18490,7 +18539,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
- .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, field_name_len)).toIntern(),
} });
};
@@ -18499,7 +18548,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const alignment = switch (struct_type.layout) {
.@"packed" => .none,
else => try sema.structFieldAlignment(
- struct_type.fieldAlign(ip, i),
+ struct_type.fieldAlign(ip, field_index),
field_ty,
struct_type.layout,
),
@@ -18569,7 +18618,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
(try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "ContainerLayout"),
+ try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(decl_index);
const decl = mod.declPtr(decl_index);
@@ -18605,7 +18654,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, "Opaque"),
+ try ip.getOrPutString(gpa, "Opaque", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index);
const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index);
@@ -18648,7 +18697,7 @@ fn typeInfoDecls(
block,
src,
type_info_ty.getNamespaceIndex(mod),
- try mod.intern_pool.getOrPutString(gpa, "Declaration"),
+ try mod.intern_pool.getOrPutString(gpa, "Declaration", .no_embedded_nulls),
)).?;
try sema.ensureDeclAnalyzed(declaration_ty_decl_index);
const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index);
@@ -18722,16 +18771,15 @@ fn typeInfoNamespaceDecls(
}
if (decl.kind != .named) continue;
const name_val = v: {
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupeZ(u8, ip.stringToSlice(decl.name));
+ const decl_name_len = decl.name.length(ip);
const new_decl_ty = try mod.arrayType(.{
- .len = name.len,
+ .len = decl_name_len,
.sentinel = .zero_u8,
.child = .u8_type,
});
const new_decl_val = try mod.intern(.{ .aggregate = .{
.ty = new_decl_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = decl.name.toString() },
} });
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
@@ -18742,7 +18790,7 @@ fn typeInfoNamespaceDecls(
.val = new_decl_val,
} },
} }),
- .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ .len = (try mod.intValue(Type.usize, decl_name_len)).toIntern(),
} });
};
@@ -19385,7 +19433,11 @@ fn zirRetErrValue(
) CompileError!void {
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
- const err_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ const err_name = try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ inst_data.get(sema.code),
+ .no_embedded_nulls,
+ );
_ = try mod.getErrorValue(err_name);
const src = inst_data.src();
// Return the error code from the function.
@@ -20072,7 +20124,11 @@ fn zirStructInit(
const field_type_data = zir_datas[@intFromEnum(item.data.field_type)].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
- const field_name = try ip.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
+ const field_name = try ip.getOrPutString(
+ gpa,
+ sema.code.nullTerminatedString(field_type_extra.name_start),
+ .no_embedded_nulls,
+ );
const field_index = if (resolved_ty.isTuple(mod))
try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
else
@@ -20109,7 +20165,11 @@ fn zirStructInit(
const field_type_data = zir_datas[@intFromEnum(item.data.field_type)].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
- const field_name = try ip.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
+ const field_name = try ip.getOrPutString(
+ gpa,
+ sema.code.nullTerminatedString(field_type_extra.name_start),
+ .no_embedded_nulls,
+ );
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
@@ -20417,8 +20477,7 @@ fn structInitAnon(
},
};
- const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
- field_name.* = name_ip;
+ field_name.* = try mod.intern_pool.getOrPutString(gpa, name, .no_embedded_nulls);
const init = try sema.resolveInst(item.data.init);
field_ty.* = sema.typeOf(init).toIntern();
@@ -20809,7 +20868,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
};
const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(mod);
const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
- const field_name = try ip.getOrPutString(sema.gpa, zir_field_name);
+ const field_name = try ip.getOrPutString(sema.gpa, zir_field_name, .no_embedded_nulls);
return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
}
@@ -20975,7 +21034,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name;
- return sema.addStrLit(sema.mod.intern_pool.stringToSlice(err_name));
+ return sema.addNullTerminatedStrLit(err_name);
}
// Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
@@ -21093,7 +21152,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.EnumLiteral => {
const val = try sema.resolveConstDefinedValue(block, .unneeded, operand, undefined);
const tag_name = ip.indexToKey(val.toIntern()).enum_literal;
- return sema.addStrLit(ip.stringToSlice(tag_name));
+ return sema.addNullTerminatedStrLit(tag_name);
},
.Enum => operand_ty,
.Union => operand_ty.unionTagType(mod) orelse
@@ -21127,7 +21186,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
};
// TODO: write something like getCoercedInts to avoid needing to dupe
const field_name = enum_ty.enumFieldName(field_index, mod);
- return sema.addStrLit(ip.stringToSlice(field_name));
+ return sema.addNullTerminatedStrLit(field_name);
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
@@ -21179,11 +21238,11 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const signedness_val = try Value.fromInterned(union_val.val).fieldValue(
mod,
- struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
+ struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness", .no_embedded_nulls)).?,
);
const bits_val = try Value.fromInterned(union_val.val).fieldValue(
mod,
- struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits")).?,
+ struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits", .no_embedded_nulls)).?,
);
const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
@@ -21195,11 +21254,11 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "len"),
+ try ip.getOrPutString(gpa, "len", .no_embedded_nulls),
).?);
const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "child"),
+ try ip.getOrPutString(gpa, "child", .no_embedded_nulls),
).?);
const len: u32 = @intCast(try len_val.toUnsignedIntAdvanced(sema));
@@ -21217,7 +21276,7 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const bits_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "bits"),
+ try ip.getOrPutString(gpa, "bits", .no_embedded_nulls),
).?);
const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema));
@@ -21235,35 +21294,35 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const size_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "size"),
+ try ip.getOrPutString(gpa, "size", .no_embedded_nulls),
).?);
const is_const_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_const"),
+ try ip.getOrPutString(gpa, "is_const", .no_embedded_nulls),
).?);
const is_volatile_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_volatile"),
+ try ip.getOrPutString(gpa, "is_volatile", .no_embedded_nulls),
).?);
const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "alignment"),
+ try ip.getOrPutString(gpa, "alignment", .no_embedded_nulls),
).?);
const address_space_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "address_space"),
+ try ip.getOrPutString(gpa, "address_space", .no_embedded_nulls),
).?);
const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "child"),
+ try ip.getOrPutString(gpa, "child", .no_embedded_nulls),
).?);
const is_allowzero_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_allowzero"),
+ try ip.getOrPutString(gpa, "is_allowzero", .no_embedded_nulls),
).?);
const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "sentinel"),
+ try ip.getOrPutString(gpa, "sentinel", .no_embedded_nulls),
).?);
if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
@@ -21341,15 +21400,15 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "len"),
+ try ip.getOrPutString(gpa, "len", .no_embedded_nulls),
).?);
const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "child"),
+ try ip.getOrPutString(gpa, "child", .no_embedded_nulls),
).?);
const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "sentinel"),
+ try ip.getOrPutString(gpa, "sentinel", .no_embedded_nulls),
).?);
const len = try len_val.toUnsignedIntAdvanced(sema);
@@ -21370,7 +21429,7 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "child"),
+ try ip.getOrPutString(gpa, "child", .no_embedded_nulls),
).?);
const child_ty = child_val.toType();
@@ -21382,11 +21441,11 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const error_set_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "error_set"),
+ try ip.getOrPutString(gpa, "error_set", .no_embedded_nulls),
).?);
const payload_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "payload"),
+ try ip.getOrPutString(gpa, "payload", .no_embedded_nulls),
).?);
const error_set_ty = error_set_val.toType();
@@ -21415,7 +21474,7 @@ fn zirReify(
const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "name"),
+ try ip.getOrPutString(gpa, "name", .no_embedded_nulls),
).?);
const name = try sema.sliceToIpString(block, src, name_val, .{
@@ -21437,23 +21496,23 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "layout"),
+ try ip.getOrPutString(gpa, "layout", .no_embedded_nulls),
).?);
const backing_integer_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "backing_integer"),
+ try ip.getOrPutString(gpa, "backing_integer", .no_embedded_nulls),
).?);
const fields_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "fields"),
+ try ip.getOrPutString(gpa, "fields", .no_embedded_nulls),
).?);
const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "decls"),
+ try ip.getOrPutString(gpa, "decls", .no_embedded_nulls),
).?);
const is_tuple_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_tuple"),
+ try ip.getOrPutString(gpa, "is_tuple", .no_embedded_nulls),
).?);
const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
@@ -21477,19 +21536,19 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "tag_type"),
+ try ip.getOrPutString(gpa, "tag_type", .no_embedded_nulls),
).?);
const fields_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "fields"),
+ try ip.getOrPutString(gpa, "fields", .no_embedded_nulls),
).?);
const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "decls"),
+ try ip.getOrPutString(gpa, "decls", .no_embedded_nulls),
).?);
const is_exhaustive_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_exhaustive"),
+ try ip.getOrPutString(gpa, "is_exhaustive", .no_embedded_nulls),
).?);
if (try decls_val.sliceLen(sema) > 0) {
@@ -21506,7 +21565,7 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "decls"),
+ try ip.getOrPutString(gpa, "decls", .no_embedded_nulls),
).?);
// Decls
@@ -21544,19 +21603,19 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "layout"),
+ try ip.getOrPutString(gpa, "layout", .no_embedded_nulls),
).?);
const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "tag_type"),
+ try ip.getOrPutString(gpa, "tag_type", .no_embedded_nulls),
).?);
const fields_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "fields"),
+ try ip.getOrPutString(gpa, "fields", .no_embedded_nulls),
).?);
const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "decls"),
+ try ip.getOrPutString(gpa, "decls", .no_embedded_nulls),
).?);
if (try decls_val.sliceLen(sema) > 0) {
@@ -21574,23 +21633,23 @@ fn zirReify(
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "calling_convention"),
+ try ip.getOrPutString(gpa, "calling_convention", .no_embedded_nulls),
).?);
const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_generic"),
+ try ip.getOrPutString(gpa, "is_generic", .no_embedded_nulls),
).?);
const is_var_args_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_var_args"),
+ try ip.getOrPutString(gpa, "is_var_args", .no_embedded_nulls),
).?);
const return_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "return_type"),
+ try ip.getOrPutString(gpa, "return_type", .no_embedded_nulls),
).?);
const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "params"),
+ try ip.getOrPutString(gpa, "params", .no_embedded_nulls),
).?);
const is_generic = is_generic_val.toBool();
@@ -21620,15 +21679,15 @@ fn zirReify(
const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_generic"),
+ try ip.getOrPutString(gpa, "is_generic", .no_embedded_nulls),
).?);
const param_is_noalias_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "is_noalias"),
+ try ip.getOrPutString(gpa, "is_noalias", .no_embedded_nulls),
).?);
const opt_param_type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
- try ip.getOrPutString(gpa, "type"),
+ try ip.getOrPutString(gpa, "type", .no_embedded_nulls),
).?);
if (param_is_generic_val.toBool()) {
@@ -22366,13 +22425,14 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
+ const ip = &mod.intern_pool;
+
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, ty_src, inst_data.operand);
- var bytes = std.ArrayList(u8).init(sema.arena);
- try ty.print(bytes.writer(), mod);
- return addStrLitNoAlias(sema, bytes.items);
+ const type_name = try ip.getOrPutStringFmt(sema.gpa, "{}", .{ty.fmt(mod)}, .no_embedded_nulls);
+ return sema.addNullTerminatedStrLit(type_name);
}
fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -23507,7 +23567,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
}
const field_index = if (ty.isTuple(mod)) blk: {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
}
break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
@@ -23977,18 +24037,18 @@ fn resolveExportOptions(
const section_src = sema.maybeOptionsSrc(block, src, "section");
const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");
- const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
+ const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name", .no_embedded_nulls), name_src);
const name = try sema.toConstString(block, name_src, name_operand, .{
.needed_comptime_reason = "name of exported value must be comptime-known",
});
- const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);
+ const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage", .no_embedded_nulls), linkage_src);
const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{
.needed_comptime_reason = "linkage of exported value must be comptime-known",
});
const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
- const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "section"), section_src);
+ const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "section", .no_embedded_nulls), section_src);
const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{
.needed_comptime_reason = "linksection of exported value must be comptime-known",
});
@@ -23999,7 +24059,7 @@ fn resolveExportOptions(
else
null;
- const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "visibility"), visibility_src);
+ const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "visibility", .no_embedded_nulls), visibility_src);
const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{
.needed_comptime_reason = "visibility of exported value must be comptime-known",
});
@@ -24016,9 +24076,9 @@ fn resolveExportOptions(
}
return .{
- .name = try ip.getOrPutString(gpa, name),
+ .name = try ip.getOrPutString(gpa, name, .no_embedded_nulls),
.linkage = linkage,
- .section = try ip.getOrPutStringOpt(gpa, section),
+ .section = try ip.getOrPutStringOpt(gpa, section, .no_embedded_nulls),
.visibility = visibility,
};
}
@@ -24896,7 +24956,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
const field_index = switch (parent_ty.zigTypeTag(mod)) {
.Struct => blk: {
if (parent_ty.isTuple(mod)) {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
return sema.fail(block, inst_src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
}
break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, field_name_src);
@@ -25578,7 +25638,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const runtime_src = rs: {
const ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src;
- const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len"), dest_src);
+ const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len", .no_embedded_nulls), dest_src);
const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;
const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?;
const len = try sema.usizeCast(block, dest_src, len_u64);
@@ -25708,7 +25768,7 @@ fn zirVarExtended(
.ty = var_ty.toIntern(),
.init = init_val,
.decl = sema.owner_decl_index,
- .lib_name = try mod.intern_pool.getOrPutStringOpt(sema.gpa, lib_name),
+ .lib_name = try mod.intern_pool.getOrPutStringOpt(sema.gpa, lib_name, .no_embedded_nulls),
.is_extern = small.is_extern,
.is_const = small.is_const,
.is_threadlocal = small.is_threadlocal,
@@ -26076,17 +26136,17 @@ fn resolvePrefetchOptions(
const locality_src = sema.maybeOptionsSrc(block, src, "locality");
const cache_src = sema.maybeOptionsSrc(block, src, "cache");
- const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "rw"), rw_src);
+ const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "rw", .no_embedded_nulls), rw_src);
const rw_val = try sema.resolveConstDefinedValue(block, rw_src, rw, .{
.needed_comptime_reason = "prefetch read/write must be comptime-known",
});
- const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "locality"), locality_src);
+ const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "locality", .no_embedded_nulls), locality_src);
const locality_val = try sema.resolveConstDefinedValue(block, locality_src, locality, .{
.needed_comptime_reason = "prefetch locality must be comptime-known",
});
- const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "cache"), cache_src);
+ const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "cache", .no_embedded_nulls), cache_src);
const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{
.needed_comptime_reason = "prefetch cache must be comptime-known",
});
@@ -26155,23 +26215,23 @@ fn resolveExternOptions(
const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");
- const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
+ const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name", .no_embedded_nulls), name_src);
const name = try sema.toConstString(block, name_src, name_ref, .{
.needed_comptime_reason = "name of the extern symbol must be comptime-known",
});
- const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src);
+ const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name", .no_embedded_nulls), library_src);
const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{
.needed_comptime_reason = "library in which extern symbol is must be comptime-known",
});
- const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);
+ const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage", .no_embedded_nulls), linkage_src);
const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{
.needed_comptime_reason = "linkage of the extern symbol must be comptime-known",
});
const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
- const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "is_thread_local"), thread_local_src);
+ const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "is_thread_local", .no_embedded_nulls), thread_local_src);
const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{
.needed_comptime_reason = "threadlocality of the extern symbol must be comptime-known",
});
@@ -26196,8 +26256,8 @@ fn resolveExternOptions(
}
return .{
- .name = try ip.getOrPutString(gpa, name),
- .library_name = try ip.getOrPutStringOpt(gpa, library_name),
+ .name = try ip.getOrPutString(gpa, name, .no_embedded_nulls),
+ .library_name = try ip.getOrPutStringOpt(gpa, library_name, .no_embedded_nulls),
.linkage = linkage,
.is_thread_local = is_thread_local_val.toBool(),
};
@@ -26809,7 +26869,7 @@ fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !InternP
block,
.unneeded,
panic_messages_ty.getNamespaceIndex(mod),
- try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)),
+ try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id), .no_embedded_nulls),
) catch |err| switch (err) {
error.AnalysisFail, error.NeededSourceLocation => @panic("std.builtin.panic_messages is corrupt"),
error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
@@ -27129,9 +27189,9 @@ fn fieldVal(
switch (inner_ty.zigTypeTag(mod)) {
.Array => {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern());
- } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {
+ } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
const ptr_info = object_ty.ptrInfo(mod);
const result_ty = try sema.ptrType(.{
.child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(),
@@ -27160,13 +27220,13 @@ fn fieldVal(
.Pointer => {
const ptr_info = inner_ty.ptrInfo(mod);
if (ptr_info.flags.size == .Slice) {
- if (ip.stringEqlSlice(field_name, "ptr")) {
+ if (field_name.eqlSlice("ptr", ip)) {
const slice = if (is_pointer_to)
try sema.analyzeLoad(block, src, object, object_src)
else
object;
return sema.analyzeSlicePtr(block, object_src, slice, inner_ty);
- } else if (ip.stringEqlSlice(field_name, "len")) {
+ } else if (field_name.eqlSlice("len", ip)) {
const slice = if (is_pointer_to)
try sema.analyzeLoad(block, src, object, object_src)
else
@@ -27319,10 +27379,10 @@ fn fieldPtr(
switch (inner_ty.zigTypeTag(mod)) {
.Array => {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
const int_val = try mod.intValue(Type.usize, inner_ty.arrayLen(mod));
return anonDeclRef(sema, int_val.toIntern());
- } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {
+ } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
const ptr_info = object_ty.ptrInfo(mod);
const new_ptr_ty = try sema.ptrType(.{
.child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(),
@@ -27370,7 +27430,7 @@ fn fieldPtr(
const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty;
- if (ip.stringEqlSlice(field_name, "ptr")) {
+ if (field_name.eqlSlice("ptr", ip)) {
const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
const result_ty = try sema.ptrType(.{
@@ -27396,7 +27456,7 @@ fn fieldPtr(
const field_ptr = try block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
return field_ptr;
- } else if (ip.stringEqlSlice(field_name, "len")) {
+ } else if (field_name.eqlSlice("len", ip)) {
const result_ty = try sema.ptrType(.{
.child = .usize_type,
.flags = .{
@@ -27584,7 +27644,7 @@ fn fieldCallBind(
return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
} else if (concrete_ty.isTuple(mod)) {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) };
}
if (field_name.toUnsigned(ip)) |field_index| {
@@ -27808,7 +27868,7 @@ fn structFieldPtr(
try sema.resolveStructLayout(struct_ty);
if (struct_ty.isTuple(mod)) {
- if (ip.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", ip)) {
const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod));
return sema.analyzeRef(block, src, len_inst);
}
@@ -28023,7 +28083,7 @@ fn tupleFieldVal(
tuple_ty: Type,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
- if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
+ if (field_name.eqlSlice("len", &mod.intern_pool)) {
return mod.intRef(Type.usize, tuple_ty.structFieldCount(mod));
}
const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src);
@@ -28039,16 +28099,17 @@ fn tupleFieldIndex(
field_name_src: LazySrcLoc,
) CompileError!u32 {
const mod = sema.mod;
- assert(!mod.intern_pool.stringEqlSlice(field_name, "len"));
- if (field_name.toUnsigned(&mod.intern_pool)) |field_index| {
+ const ip = &mod.intern_pool;
+ assert(!field_name.eqlSlice("len", ip));
+ if (field_name.toUnsigned(ip)) |field_index| {
if (field_index < tuple_ty.structFieldCount(mod)) return field_index;
return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{
- field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod),
+ field_name.fmt(ip), tuple_ty.fmt(mod),
});
}
return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{
- field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod),
+ field_name.fmt(ip), tuple_ty.fmt(mod),
});
}
@@ -28076,7 +28137,7 @@ fn tupleFieldValByIndex(
return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) {
.undef => mod.undefRef(field_ty),
.aggregate => |aggregate| Air.internedToRef(switch (aggregate.storage) {
- .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]),
+ .bytes => |bytes| try mod.intValue(Type.u8, bytes.at(field_index, &mod.intern_pool)),
.elems => |elems| Value.fromInterned(elems[field_index]),
.repeated_elem => |elem| Value.fromInterned(elem),
}.toIntern()),
@@ -32266,38 +32327,36 @@ fn coerceTupleToStruct(
.struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
else => unreachable,
};
- for (0..field_count) |field_index_usize| {
- const field_i: u32 = @intCast(field_index_usize);
+ for (0..field_count) |tuple_field_index| {
const field_src = inst_src; // TODO better source location
- // https://github.com/ziglang/zig/issues/15709
const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
- anon_struct_type.names.get(ip)[field_i]
+ anon_struct_type.names.get(ip)[tuple_field_index]
else
- try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
- .struct_type => ip.loadStructType(inst_ty.toIntern()).field_names.get(ip)[field_i],
+ try ip.getOrPutStringFmt(sema.gpa, "{d}", .{tuple_field_index}, .no_embedded_nulls),
+ .struct_type => ip.loadStructType(inst_ty.toIntern()).field_names.get(ip)[tuple_field_index],
else => unreachable,
};
- const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
- const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
- const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
- field_refs[field_index] = coerced;
- if (struct_type.fieldIsComptime(ip, field_index)) {
+ const struct_field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
+ const struct_field_ty = Type.fromInterned(struct_type.field_types.get(ip)[struct_field_index]);
+ const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, @intCast(tuple_field_index));
+ const coerced = try sema.coerce(block, struct_field_ty, elem_ref, field_src);
+ field_refs[struct_field_index] = coerced;
+ if (struct_type.fieldIsComptime(ip, struct_field_index)) {
const init_val = (try sema.resolveValue(coerced)) orelse {
return sema.failWithNeededComptime(block, field_src, .{
.needed_comptime_reason = "value stored in comptime field must be comptime-known",
});
};
- const field_init = Value.fromInterned(struct_type.field_inits.get(ip)[field_index]);
- if (!init_val.eql(field_init, field_ty, sema.mod)) {
- return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
+ const field_init = Value.fromInterned(struct_type.field_inits.get(ip)[struct_field_index]);
+ if (!init_val.eql(field_init, struct_field_ty, sema.mod)) {
+ return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, tuple_field_index);
}
}
if (runtime_src == null) {
if (try sema.resolveValue(coerced)) |field_val| {
- field_vals[field_index] = field_val.toIntern();
+ field_vals[struct_field_index] = field_val.toIntern();
} else {
runtime_src = field_src;
}
@@ -32382,24 +32441,23 @@ fn coerceTupleToTuple(
for (0..dest_field_count) |field_index_usize| {
const field_i: u32 = @intCast(field_index_usize);
const field_src = inst_src; // TODO better source location
- // https://github.com/ziglang/zig/issues/15709
const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
anon_struct_type.names.get(ip)[field_i]
else
- try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
+ try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}, .no_embedded_nulls),
.struct_type => s: {
const struct_type = ip.loadStructType(inst_ty.toIntern());
if (struct_type.field_names.len > 0) {
break :s struct_type.field_names.get(ip)[field_i];
} else {
- break :s try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i});
+ break :s try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}, .no_embedded_nulls);
}
},
else => unreachable,
};
- if (ip.stringEqlSlice(field_name, "len"))
+ if (field_name.eqlSlice("len", ip))
return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
@@ -34196,7 +34254,7 @@ const PeerResolveResult = union(enum) {
/// There was an error when resolving the type of a struct or tuple field.
field_error: struct {
/// The name of the field which caused the failure.
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
/// The type of this field in each peer.
field_types: []Type,
/// The error from resolving the field type. Guaranteed not to be `success`.
@@ -34237,8 +34295,8 @@ const PeerResolveResult = union(enum) {
};
},
.field_error => |field_error| {
- const fmt = "struct field '{s}' has conflicting types";
- const args = .{field_error.field_name};
+ const fmt = "struct field '{}' has conflicting types";
+ const args = .{field_error.field_name.fmt(&mod.intern_pool)};
if (opt_msg) |msg| {
try sema.errNote(block, src, msg, fmt, args);
} else {
@@ -35321,7 +35379,7 @@ fn resolvePeerTypesInner(
const sub_peer_tys = try sema.arena.alloc(?Type, peer_tys.len);
const sub_peer_vals = try sema.arena.alloc(?Value, peer_vals.len);
- for (field_types, field_vals, 0..) |*field_ty, *field_val, field_idx| {
+ for (field_types, field_vals, 0..) |*field_ty, *field_val, field_index| {
// Fill buffers with types and values of the field
for (peer_tys, peer_vals, sub_peer_tys, sub_peer_vals) |opt_ty, opt_val, *peer_field_ty, *peer_field_val| {
const ty = opt_ty orelse {
@@ -35329,8 +35387,8 @@ fn resolvePeerTypesInner(
peer_field_val.* = null;
continue;
};
- peer_field_ty.* = ty.structFieldType(field_idx, mod);
- peer_field_val.* = if (opt_val) |val| try val.fieldValue(mod, field_idx) else null;
+ peer_field_ty.* = ty.structFieldType(field_index, mod);
+ peer_field_val.* = if (opt_val) |val| try val.fieldValue(mod, field_index) else null;
}
// Resolve field type recursively
@@ -35339,9 +35397,10 @@ fn resolvePeerTypesInner(
else => |result| {
const result_buf = try sema.arena.create(PeerResolveResult);
result_buf.* = result;
- const field_name = if (is_tuple) name: {
- break :name try std.fmt.allocPrint(sema.arena, "{d}", .{field_idx});
- } else try sema.arena.dupe(u8, ip.stringToSlice(field_names[field_idx]));
+ const field_name = if (is_tuple)
+ try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_index}, .no_embedded_nulls)
+ else
+ field_names[field_index];
// The error info needs the field types, but we can't reuse sub_peer_tys
// since the recursive call may have clobbered it.
@@ -35350,7 +35409,7 @@ fn resolvePeerTypesInner(
// Already-resolved types won't be referenced by the error so it's fine
// to leave them undefined.
const ty = opt_ty orelse continue;
- peer_field_ty.* = ty.structFieldType(field_idx, mod);
+ peer_field_ty.* = ty.structFieldType(field_index, mod);
}
return .{ .field_error = .{
@@ -35369,7 +35428,7 @@ fn resolvePeerTypesInner(
const struct_ty = opt_ty orelse continue;
try sema.resolveStructFieldInits(struct_ty);
- const uncoerced_field_val = try struct_ty.structFieldValueComptime(mod, field_idx) orelse {
+ const uncoerced_field_val = try struct_ty.structFieldValueComptime(mod, field_index) orelse {
comptime_val = null;
break;
};
@@ -36811,7 +36870,7 @@ fn semaStructFields(
// This string needs to outlive the ZIR code.
if (opt_field_name_zir) |field_name_zir| {
- const field_name = try ip.getOrPutString(gpa, field_name_zir);
+ const field_name = try ip.getOrPutString(gpa, field_name_zir, .no_embedded_nulls);
assert(struct_type.addFieldName(ip, field_name) == null);
}
@@ -37342,7 +37401,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
}
// This string needs to outlive the ZIR code.
- const field_name = try ip.getOrPutString(gpa, field_name_zir);
+ const field_name = try ip.getOrPutString(gpa, field_name_zir, .no_embedded_nulls);
if (enum_field_names.len != 0) {
enum_field_names[field_i] = field_name;
}
@@ -37528,7 +37587,12 @@ fn generateUnionTagTypeNumbered(
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
errdefer mod.destroyDecl(new_decl_index);
const fqn = try union_owner_decl.fullyQualifiedName(mod);
- const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
+ const name = try ip.getOrPutStringFmt(
+ gpa,
+ "@typeInfo({}).Union.tag_type.?",
+ .{fqn.fmt(ip)},
+ .no_embedded_nulls,
+ );
try mod.initNewAnonDecl(
new_decl_index,
src_decl.src_line,
@@ -37574,7 +37638,12 @@ fn generateUnionTagTypeSimple(
const src_decl = mod.declPtr(block.src_decl);
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
errdefer mod.destroyDecl(new_decl_index);
- const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
+ const name = try ip.getOrPutStringFmt(
+ gpa,
+ "@typeInfo({}).Union.tag_type.?",
+ .{fqn.fmt(ip)},
+ .no_embedded_nulls,
+ );
try mod.initNewAnonDecl(
new_decl_index,
src_decl.src_line,
@@ -37638,7 +37707,7 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
block,
src,
mod.declPtr(std_file.root_decl.unwrap().?).src_namespace.toOptional(),
- try ip.getOrPutString(gpa, "builtin"),
+ try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls),
)) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst, src);
const builtin_ty = sema.analyzeAsType(block, src, builtin_inst) catch |err| switch (err) {
@@ -37649,7 +37718,7 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
block,
src,
builtin_ty.getNamespaceIndex(mod),
- try ip.getOrPutString(gpa, name),
+ try ip.getOrPutString(gpa, name, .no_embedded_nulls),
)) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});
return decl_index;
}
@@ -38820,7 +38889,7 @@ fn intFitsInType(
.aggregate => |aggregate| {
assert(ty.zigTypeTag(mod) == .Vector);
return switch (aggregate.storage) {
- .bytes => |bytes| for (bytes, 0..) |byte, i| {
+ .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(mod), &mod.intern_pool), 0..) |byte, i| {
if (byte == 0) continue;
const actual_needed_bits = std.math.log2(byte) + 1 + @intFromBool(info.signedness == .signed);
if (info.bits >= actual_needed_bits) continue;
diff --git a/src/Value.zig b/src/Value.zig
index 7a9775e198..0f8dc5f7dc 100644
--- a/src/Value.zig
+++ b/src/Value.zig
@@ -52,30 +52,31 @@ pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminated
assert(ty.zigTypeTag(mod) == .Array);
assert(ty.childType(mod).toIntern() == .u8_type);
const ip = &mod.intern_pool;
- return switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
- .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),
- .elems => try arrayToIpString(val, ty.arrayLen(mod), mod),
+ switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
+ .bytes => |bytes| return bytes.toNullTerminatedString(ty.arrayLen(mod), ip),
+ .elems => return arrayToIpString(val, ty.arrayLen(mod), mod),
.repeated_elem => |elem| {
- const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));
- const len = @as(usize, @intCast(ty.arrayLen(mod)));
+ const byte: u8 = @intCast(Value.fromInterned(elem).toUnsignedInt(mod));
+ const len: usize = @intCast(ty.arrayLen(mod));
try ip.string_bytes.appendNTimes(mod.gpa, byte, len);
- return ip.getOrPutTrailingString(mod.gpa, len);
+ return ip.getOrPutTrailingString(mod.gpa, len, .no_embedded_nulls);
},
- };
+ }
}
/// Asserts that the value is representable as an array of bytes.
/// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 {
- return switch (mod.intern_pool.indexToKey(val.toIntern())) {
- .enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)),
+ const ip = &mod.intern_pool;
+ return switch (ip.indexToKey(val.toIntern())) {
+ .enum_literal => |enum_literal| allocator.dupe(u8, enum_literal.toSlice(ip)),
.slice => |slice| try arrayToAllocatedBytes(val, Value.fromInterned(slice.len).toUnsignedInt(mod), allocator, mod),
.aggregate => |aggregate| switch (aggregate.storage) {
- .bytes => |bytes| try allocator.dupe(u8, bytes),
+ .bytes => |bytes| try allocator.dupe(u8, bytes.toSlice(ty.arrayLenIncludingSentinel(mod), ip)),
.elems => try arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod),
.repeated_elem => |elem| {
- const byte = @as(u8, @intCast(Value.fromInterned(elem).toUnsignedInt(mod)));
- const result = try allocator.alloc(u8, @as(usize, @intCast(ty.arrayLen(mod))));
+ const byte: u8 = @intCast(Value.fromInterned(elem).toUnsignedInt(mod));
+ const result = try allocator.alloc(u8, @intCast(ty.arrayLen(mod)));
@memset(result, byte);
return result;
},
@@ -85,10 +86,10 @@ pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module
}
fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, mod: *Module) ![]u8 {
- const result = try allocator.alloc(u8, @as(usize, @intCast(len)));
+ const result = try allocator.alloc(u8, @intCast(len));
for (result, 0..) |*elem, i| {
const elem_val = try val.elemValue(mod, i);
- elem.* = @as(u8, @intCast(elem_val.toUnsignedInt(mod)));
+ elem.* = @intCast(elem_val.toUnsignedInt(mod));
}
return result;
}
@@ -96,7 +97,7 @@ fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, mod: *Modul
fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTerminatedString {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
- const len = @as(usize, @intCast(len_u64));
+ const len: usize = @intCast(len_u64);
try ip.string_bytes.ensureUnusedCapacity(gpa, len);
for (0..len) |i| {
// I don't think elemValue has the possibility to affect ip.string_bytes. Let's
@@ -104,10 +105,10 @@ fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTermi
const prev = ip.string_bytes.items.len;
const elem_val = try val.elemValue(mod, i);
assert(ip.string_bytes.items.len == prev);
- const byte = @as(u8, @intCast(elem_val.toUnsignedInt(mod)));
+ const byte: u8 = @intCast(elem_val.toUnsignedInt(mod));
ip.string_bytes.appendAssumeCapacity(byte);
}
- return ip.getOrPutTrailingString(gpa, len);
+ return ip.getOrPutTrailingString(gpa, len, .no_embedded_nulls);
}
pub fn fromInterned(i: InternPool.Index) Value {
@@ -256,7 +257,7 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);
if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty);
- return base_addr + struct_ty.structFieldOffset(@as(usize, @intCast(field.index)), mod);
+ return base_addr + struct_ty.structFieldOffset(@intCast(field.index), mod);
},
else => null,
},
@@ -351,17 +352,17 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{
bigint.writeTwosComplement(buffer[0..byte_count], endian);
},
.Float => switch (ty.floatBits(target)) {
- 16 => std.mem.writeInt(u16, buffer[0..2], @as(u16, @bitCast(val.toFloat(f16, mod))), endian),
- 32 => std.mem.writeInt(u32, buffer[0..4], @as(u32, @bitCast(val.toFloat(f32, mod))), endian),
- 64 => std.mem.writeInt(u64, buffer[0..8], @as(u64, @bitCast(val.toFloat(f64, mod))), endian),
- 80 => std.mem.writeInt(u80, buffer[0..10], @as(u80, @bitCast(val.toFloat(f80, mod))), endian),
- 128 => std.mem.writeInt(u128, buffer[0..16], @as(u128, @bitCast(val.toFloat(f128, mod))), endian),
+ 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(val.toFloat(f16, mod)), endian),
+ 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(val.toFloat(f32, mod)), endian),
+ 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(val.toFloat(f64, mod)), endian),
+ 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(val.toFloat(f80, mod)), endian),
+ 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(val.toFloat(f128, mod)), endian),
else => unreachable,
},
.Array => {
const len = ty.arrayLen(mod);
const elem_ty = ty.childType(mod);
- const elem_size = @as(usize, @intCast(elem_ty.abiSize(mod)));
+ const elem_size: usize = @intCast(elem_ty.abiSize(mod));
var elem_i: usize = 0;
var buf_off: usize = 0;
while (elem_i < len) : (elem_i += 1) {
@@ -380,17 +381,17 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{
const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout;
switch (struct_type.layout) {
.auto => return error.IllDefinedMemoryLayout,
- .@"extern" => for (0..struct_type.field_types.len) |i| {
- const off: usize = @intCast(ty.structFieldOffset(i, mod));
+ .@"extern" => for (0..struct_type.field_types.len) |field_index| {
+ const off: usize = @intCast(ty.structFieldOffset(field_index, mod));
const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| {
- buffer[off] = bytes[i];
+ buffer[off] = bytes.at(field_index, ip);
continue;
},
- .elems => |elems| elems[i],
+ .elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
});
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
+ const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
try writeToMemory(field_val, field_ty, mod, buffer[off..]);
},
.@"packed" => {
@@ -423,7 +424,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{
const field_index = mod.unionTagFieldIndex(union_obj, union_tag).?;
const field_type = Type.fromInterned(union_obj.field_types.get(&mod.intern_pool)[field_index]);
const field_val = try val.fieldValue(mod, field_index);
- const byte_count = @as(usize, @intCast(field_type.abiSize(mod)));
+ const byte_count: usize = @intCast(field_type.abiSize(mod));
return writeToMemory(field_val, field_type, mod, buffer[0..byte_count]);
} else {
const backing_ty = try ty.unionBackingType(mod);
@@ -471,7 +472,7 @@ pub fn writeToPackedMemory(
const target = mod.getTarget();
const endian = target.cpu.arch.endian();
if (val.isUndef(mod)) {
- const bit_size = @as(usize, @intCast(ty.bitSize(mod)));
+ const bit_size: usize = @intCast(ty.bitSize(mod));
std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian);
return;
}
@@ -507,17 +508,17 @@ pub fn writeToPackedMemory(
}
},
.Float => switch (ty.floatBits(target)) {
- 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @as(u16, @bitCast(val.toFloat(f16, mod))), endian),
- 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @as(u32, @bitCast(val.toFloat(f32, mod))), endian),
- 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @as(u64, @bitCast(val.toFloat(f64, mod))), endian),
- 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @as(u80, @bitCast(val.toFloat(f80, mod))), endian),
- 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @as(u128, @bitCast(val.toFloat(f128, mod))), endian),
+ 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @bitCast(val.toFloat(f16, mod)), endian),
+ 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @bitCast(val.toFloat(f32, mod)), endian),
+ 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @bitCast(val.toFloat(f64, mod)), endian),
+ 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @bitCast(val.toFloat(f80, mod)), endian),
+ 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(val.toFloat(f128, mod)), endian),
else => unreachable,
},
.Vector => {
const elem_ty = ty.childType(mod);
- const elem_bit_size = @as(u16, @intCast(elem_ty.bitSize(mod)));
- const len = @as(usize, @intCast(ty.arrayLen(mod)));
+ const elem_bit_size: u16 = @intCast(elem_ty.bitSize(mod));
+ const len: usize = @intCast(ty.arrayLen(mod));
var bits: u16 = 0;
var elem_i: usize = 0;
@@ -644,22 +645,22 @@ pub fn readFromMemory(
.Float => return Value.fromInterned((try mod.intern(.{ .float = .{
.ty = ty.toIntern(),
.storage = switch (ty.floatBits(target)) {
- 16 => .{ .f16 = @as(f16, @bitCast(std.mem.readInt(u16, buffer[0..2], endian))) },
- 32 => .{ .f32 = @as(f32, @bitCast(std.mem.readInt(u32, buffer[0..4], endian))) },
- 64 => .{ .f64 = @as(f64, @bitCast(std.mem.readInt(u64, buffer[0..8], endian))) },
- 80 => .{ .f80 = @as(f80, @bitCast(std.mem.readInt(u80, buffer[0..10], endian))) },
- 128 => .{ .f128 = @as(f128, @bitCast(std.mem.readInt(u128, buffer[0..16], endian))) },
+ 16 => .{ .f16 = @bitCast(std.mem.readInt(u16, buffer[0..2], endian)) },
+ 32 => .{ .f32 = @bitCast(std.mem.readInt(u32, buffer[0..4], endian)) },
+ 64 => .{ .f64 = @bitCast(std.mem.readInt(u64, buffer[0..8], endian)) },
+ 80 => .{ .f80 = @bitCast(std.mem.readInt(u80, buffer[0..10], endian)) },
+ 128 => .{ .f128 = @bitCast(std.mem.readInt(u128, buffer[0..16], endian)) },
else => unreachable,
},
} }))),
.Array => {
const elem_ty = ty.childType(mod);
const elem_size = elem_ty.abiSize(mod);
- const elems = try arena.alloc(InternPool.Index, @as(usize, @intCast(ty.arrayLen(mod))));
+ const elems = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(mod)));
var offset: usize = 0;
for (elems) |*elem| {
elem.* = (try readFromMemory(elem_ty, mod, buffer[offset..], arena)).toIntern();
- offset += @as(usize, @intCast(elem_size));
+ offset += @intCast(elem_size);
}
return Value.fromInterned((try mod.intern(.{ .aggregate = .{
.ty = ty.toIntern(),
@@ -795,7 +796,7 @@ pub fn readFromPackedMemory(
};
// Slow path, we have to construct a big-int
- const abi_size = @as(usize, @intCast(ty.abiSize(mod)));
+ const abi_size: usize = @intCast(ty.abiSize(mod));
const Limb = std.math.big.Limb;
const limb_count = (abi_size + @sizeOf(Limb) - 1) / @sizeOf(Limb);
const limbs_buffer = try arena.alloc(Limb, limb_count);
@@ -812,20 +813,20 @@ pub fn readFromPackedMemory(
.Float => return Value.fromInterned((try mod.intern(.{ .float = .{
.ty = ty.toIntern(),
.storage = switch (ty.floatBits(target)) {
- 16 => .{ .f16 = @as(f16, @bitCast(std.mem.readPackedInt(u16, buffer, bit_offset, endian))) },
- 32 => .{ .f32 = @as(f32, @bitCast(std.mem.readPackedInt(u32, buffer, bit_offset, endian))) },
- 64 => .{ .f64 = @as(f64, @bitCast(std.mem.readPackedInt(u64, buffer, bit_offset, endian))) },
- 80 => .{ .f80 = @as(f80, @bitCast(std.mem.readPackedInt(u80, buffer, bit_offset, endian))) },
- 128 => .{ .f128 = @as(f128, @bitCast(std.mem.readPackedInt(u128, buffer, bit_offset, endian))) },
+ 16 => .{ .f16 = @bitCast(std.mem.readPackedInt(u16, buffer, bit_offset, endian)) },
+ 32 => .{ .f32 = @bitCast(std.mem.readPackedInt(u32, buffer, bit_offset, endian)) },
+ 64 => .{ .f64 = @bitCast(std.mem.readPackedInt(u64, buffer, bit_offset, endian)) },
+ 80 => .{ .f80 = @bitCast(std.mem.readPackedInt(u80, buffer, bit_offset, endian)) },
+ 128 => .{ .f128 = @bitCast(std.mem.readPackedInt(u128, buffer, bit_offset, endian)) },
else => unreachable,
},
} }))),
.Vector => {
const elem_ty = ty.childType(mod);
- const elems = try arena.alloc(InternPool.Index, @as(usize, @intCast(ty.arrayLen(mod))));
+ const elems = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(mod)));
var bits: u16 = 0;
- const elem_bit_size = @as(u16, @intCast(elem_ty.bitSize(mod)));
+ const elem_bit_size: u16 = @intCast(elem_ty.bitSize(mod));
for (elems, 0..) |_, i| {
// On big-endian systems, LLVM reverses the element order of vectors by default
const tgt_elem_i = if (endian == .big) elems.len - i - 1 else i;
@@ -909,7 +910,7 @@ fn bigIntToFloat(limbs: []const std.math.big.Limb, positive: bool) f128 {
var i: usize = limbs.len;
while (i != 0) {
i -= 1;
- const limb: f128 = @as(f128, @floatFromInt(limbs[i]));
+ const limb: f128 = @floatFromInt(limbs[i]);
result = @mulAdd(f128, base, result, limb);
}
if (positive) {
@@ -934,7 +935,7 @@ pub fn ctz(val: Value, ty: Type, mod: *Module) u64 {
pub fn popCount(val: Value, ty: Type, mod: *Module) u64 {
var bigint_buf: BigIntSpace = undefined;
const bigint = val.toBigInt(&bigint_buf, mod);
- return @as(u64, @intCast(bigint.popCount(ty.intInfo(mod).bits)));
+ return @intCast(bigint.popCount(ty.intInfo(mod).bits));
}
pub fn bitReverse(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value {
@@ -1191,7 +1192,7 @@ pub fn compareAllWithZeroAdvancedExtra(
inline else => |x| if (std.math.isNan(x)) return op == .neq,
},
.aggregate => |aggregate| return switch (aggregate.storage) {
- .bytes => |bytes| for (bytes) |byte| {
+ .bytes => |bytes| for (bytes.toSlice(lhs.typeOf(mod).arrayLenIncludingSentinel(mod), &mod.intern_pool)) |byte| {
if (!std.math.order(byte, 0).compare(op)) break false;
} else true,
.elems => |elems| for (elems) |elem| {
@@ -1279,7 +1280,7 @@ pub fn elemValue(val: Value, zcu: *Zcu, index: usize) Allocator.Error!Value {
if (index < len) return Value.fromInterned(switch (aggregate.storage) {
.bytes => |bytes| try zcu.intern(.{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = bytes[index] },
+ .storage = .{ .u64 = bytes.at(index, ip) },
} }),
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
@@ -1318,28 +1319,37 @@ pub fn sliceArray(
start: usize,
end: usize,
) error{OutOfMemory}!Value {
- // TODO: write something like getCoercedInts to avoid needing to dupe
const mod = sema.mod;
- const aggregate = mod.intern_pool.indexToKey(val.toIntern()).aggregate;
- return Value.fromInterned(try mod.intern(.{ .aggregate = .{
- .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) {
- .array_type => |array_type| try mod.arrayType(.{
- .len = @as(u32, @intCast(end - start)),
- .child = array_type.child,
- .sentinel = if (end == array_type.len) array_type.sentinel else .none,
- }),
- .vector_type => |vector_type| try mod.vectorType(.{
- .len = @as(u32, @intCast(end - start)),
- .child = vector_type.child,
- }),
- else => unreachable,
- }.toIntern(),
- .storage = switch (aggregate.storage) {
- .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
- .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
- .repeated_elem => |elem| .{ .repeated_elem = elem },
+ const ip = &mod.intern_pool;
+ return Value.fromInterned(try mod.intern(.{
+ .aggregate = .{
+ .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) {
+ .array_type => |array_type| try mod.arrayType(.{
+ .len = @intCast(end - start),
+ .child = array_type.child,
+ .sentinel = if (end == array_type.len) array_type.sentinel else .none,
+ }),
+ .vector_type => |vector_type| try mod.vectorType(.{
+ .len = @intCast(end - start),
+ .child = vector_type.child,
+ }),
+ else => unreachable,
+ }.toIntern(),
+ .storage = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
+ .bytes => |bytes| storage: {
+ try ip.string_bytes.ensureUnusedCapacity(sema.gpa, end - start + 1);
+ break :storage .{ .bytes = try ip.getOrPutString(
+ sema.gpa,
+ bytes.toSlice(end, ip)[start..],
+ .maybe_embedded_nulls,
+ ) };
+ },
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ .elems => |elems| .{ .elems = try sema.arena.dupe(InternPool.Index, elems[start..end]) },
+ .repeated_elem => |elem| .{ .repeated_elem = elem },
+ },
},
- } }));
+ }));
}
pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
@@ -1350,7 +1360,7 @@ pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
.aggregate => |aggregate| Value.fromInterned(switch (aggregate.storage) {
.bytes => |bytes| try mod.intern(.{ .int = .{
.ty = .u8_type,
- .storage = .{ .u64 = bytes[index] },
+ .storage = .{ .u64 = bytes.at(index, &mod.intern_pool) },
} }),
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
@@ -1461,7 +1471,7 @@ pub fn getErrorName(val: Value, mod: *const Module) InternPool.OptionalNullTermi
pub fn getErrorInt(val: Value, mod: *const Module) Module.ErrorInt {
return if (getErrorName(val, mod).unwrap()) |err_name|
- @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(err_name).?))
+ @intCast(mod.global_error_set.getIndex(err_name).?)
else
0;
}
@@ -2413,14 +2423,14 @@ pub fn intTruncBitsAsValue(
for (result_data, 0..) |*scalar, i| {
const elem_val = try val.elemValue(mod, i);
const bits_elem = try bits.elemValue(mod, i);
- scalar.* = (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @as(u16, @intCast(bits_elem.toUnsignedInt(mod))), mod)).toIntern();
+ scalar.* = (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @intCast(bits_elem.toUnsignedInt(mod)), mod)).toIntern();
}
return Value.fromInterned((try mod.intern(.{ .aggregate = .{
.ty = ty.toIntern(),
.storage = .{ .elems = result_data },
} })));
}
- return intTruncScalar(val, ty, allocator, signedness, @as(u16, @intCast(bits.toUnsignedInt(mod))), mod);
+ return intTruncScalar(val, ty, allocator, signedness, @intCast(bits.toUnsignedInt(mod)), mod);
}
pub fn intTruncScalar(
@@ -2468,7 +2478,7 @@ pub fn shlScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
- const shift = @as(usize, @intCast(rhs.toUnsignedInt(mod)));
+ const shift: usize = @intCast(rhs.toUnsignedInt(mod));
const limbs = try allocator.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
@@ -2530,7 +2540,7 @@ pub fn shlWithOverflowScalar(
const info = ty.intInfo(mod);
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
- const shift = @as(usize, @intCast(rhs.toUnsignedInt(mod)));
+ const shift: usize = @intCast(rhs.toUnsignedInt(mod));
const limbs = try allocator.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
@@ -2587,7 +2597,7 @@ pub fn shlSatScalar(
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
- const shift = @as(usize, @intCast(rhs.toUnsignedInt(mod)));
+ const shift: usize = @intCast(rhs.toUnsignedInt(mod));
const limbs = try arena.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(info.bits) + 1,
@@ -2659,7 +2669,7 @@ pub fn shrScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, mod);
- const shift = @as(usize, @intCast(rhs.toUnsignedInt(mod)));
+ const shift: usize = @intCast(rhs.toUnsignedInt(mod));
const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8));
if (result_limbs == 0) {
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index b9f8259c05..ddde72345e 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -4345,8 +4345,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
.data = .{ .reg = .x30 },
});
} else if (func_value.getExternFunc(mod)) |extern_func| {
- const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name);
+ const decl_name = mod.declPtr(extern_func.decl).name.toSlice(&mod.intern_pool);
+ const lib_name = extern_func.lib_name.toSlice(&mod.intern_pool);
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
_ = macho_file;
@panic("TODO airCall");
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 022f2f9bee..83159ec80e 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -2199,9 +2199,9 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
const atom = func.bin_file.getAtomPtr(atom_index);
const type_index = try func.bin_file.storeDeclType(extern_func.decl, func_type);
try func.bin_file.addOrUpdateImport(
- mod.intern_pool.stringToSlice(ext_decl.name),
+ ext_decl.name.toSlice(&mod.intern_pool),
atom.sym_index,
- mod.intern_pool.stringToSliceUnwrap(ext_decl.getOwnedExternFunc(mod).?.lib_name),
+ ext_decl.getOwnedExternFunc(mod).?.lib_name.toSlice(&mod.intern_pool),
type_index,
);
break :blk extern_func.decl;
@@ -7236,8 +7236,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
- const fqn = ip.stringToSlice(try mod.declPtr(enum_decl_index).fullyQualifiedName(mod));
- const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});
+ const fqn = try mod.declPtr(enum_decl_index).fullyQualifiedName(mod);
+ const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{}", .{fqn.fmt(ip)});
// check if we already generated code for this.
if (func.bin_file.findGlobalSymbol(func_name)) |loc| {
@@ -7268,17 +7268,18 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
// generate an if-else chain for each tag value as well as constant.
const tag_names = enum_ty.enumFields(mod);
for (0..tag_names.len) |tag_index| {
- const tag_name = ip.stringToSlice(tag_names.get(ip)[tag_index]);
+ const tag_name = tag_names.get(ip)[tag_index];
+ const tag_name_len = tag_name.length(ip);
// for each tag name, create an unnamed const,
// and then get a pointer to its value.
const name_ty = try mod.arrayType(.{
- .len = tag_name.len,
+ .len = tag_name_len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const name_val = try mod.intern(.{ .aggregate = .{
.ty = name_ty.toIntern(),
- .storage = .{ .bytes = tag_name },
+ .storage = .{ .bytes = tag_name.toString() },
} });
const tag_sym_index = try func.bin_file.lowerUnnamedConst(
Value.fromInterned(name_val),
@@ -7338,7 +7339,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
// store length
try writer.writeByte(std.wasm.opcode(.i32_const));
- try leb.writeULEB128(writer, @as(u32, @intCast(tag_name.len)));
+ try leb.writeULEB128(writer, @as(u32, @intCast(tag_name_len)));
try writer.writeByte(std.wasm.opcode(.i32_store));
try leb.writeULEB128(writer, encoded_alignment);
try leb.writeULEB128(writer, @as(u32, 4));
@@ -7359,7 +7360,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
// store length
try writer.writeByte(std.wasm.opcode(.i64_const));
- try leb.writeULEB128(writer, @as(u64, @intCast(tag_name.len)));
+ try leb.writeULEB128(writer, @as(u64, @intCast(tag_name_len)));
try writer.writeByte(std.wasm.opcode(.i64_store));
try leb.writeULEB128(writer, encoded_alignment);
try leb.writeULEB128(writer, @as(u32, 8));
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 7a90eacf54..c165baf7e8 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2247,7 +2247,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
var data_off: i32 = 0;
const tag_names = enum_ty.enumFields(mod);
for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| {
- const tag_name_len = ip.stringToSlice(tag_names.get(ip)[tag_index]).len;
+ const tag_name_len = tag_names.get(ip)[tag_index].length(ip);
const tag_val = try mod.enumValueFieldIndex(enum_ty, @intCast(tag_index));
const tag_mcv = try self.genTypedValue(tag_val);
try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
@@ -12314,8 +12314,8 @@ fn genCall(self: *Self, info: union(enum) {
},
.extern_func => |extern_func| {
const owner_decl = mod.declPtr(extern_func.decl);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name);
- const decl_name = mod.intern_pool.stringToSlice(owner_decl.name);
+ const lib_name = extern_func.lib_name.toSlice(&mod.intern_pool);
+ const decl_name = owner_decl.name.toSlice(&mod.intern_pool);
try self.genExternSymbolRef(.call, lib_name, decl_name);
},
else => return self.fail("TODO implement calling bitcasted functions", .{}),
diff --git a/src/codegen.zig b/src/codegen.zig
index 76be8be974..b45777564a 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -97,7 +97,7 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
_ = target;
const bits = @typeInfo(F).Float.bits;
const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } });
- const int = @as(Int, @bitCast(f));
+ const int: Int = @bitCast(f);
mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian);
}
@@ -136,24 +136,24 @@ pub fn generateLazySymbol(
if (lazy_sym.ty.isAnyError(zcu)) {
alignment.* = .@"4";
const err_names = zcu.global_error_set.keys();
- mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian);
+ mem.writeInt(u32, try code.addManyAsArray(4), @intCast(err_names.len), endian);
var offset = code.items.len;
try code.resize((1 + err_names.len + 1) * 4);
for (err_names) |err_name_nts| {
- const err_name = zcu.intern_pool.stringToSlice(err_name_nts);
- mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian);
+ const err_name = err_name_nts.toSlice(ip);
+ mem.writeInt(u32, code.items[offset..][0..4], @intCast(code.items.len), endian);
offset += 4;
try code.ensureUnusedCapacity(err_name.len + 1);
code.appendSliceAssumeCapacity(err_name);
code.appendAssumeCapacity(0);
}
- mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian);
+ mem.writeInt(u32, code.items[offset..][0..4], @intCast(code.items.len), endian);
return Result.ok;
} else if (lazy_sym.ty.zigTypeTag(zcu) == .Enum) {
alignment.* = .@"1";
const tag_names = lazy_sym.ty.enumFields(zcu);
for (0..tag_names.len) |tag_index| {
- const tag_name = zcu.intern_pool.stringToSlice(tag_names.get(ip)[tag_index]);
+ const tag_name = tag_names.get(ip)[tag_index].toSlice(ip);
try code.ensureUnusedCapacity(tag_name.len + 1);
code.appendSliceAssumeCapacity(tag_name);
code.appendAssumeCapacity(0);
@@ -241,13 +241,13 @@ pub fn generateSymbol(
},
.err => |err| {
const int = try mod.getErrorValue(err.name);
- try code.writer().writeInt(u16, @as(u16, @intCast(int)), endian);
+ try code.writer().writeInt(u16, @intCast(int), endian);
},
.error_union => |error_union| {
const payload_ty = ty.errorUnionPayload(mod);
- const err_val = switch (error_union.val) {
- .err_name => |err_name| @as(u16, @intCast(try mod.getErrorValue(err_name))),
- .payload => @as(u16, 0),
+ const err_val: u16 = switch (error_union.val) {
+ .err_name => |err_name| @intCast(try mod.getErrorValue(err_name)),
+ .payload => 0,
};
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
@@ -357,15 +357,13 @@ pub fn generateSymbol(
},
.aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
.array_type => |array_type| switch (aggregate.storage) {
- .bytes => |bytes| try code.appendSlice(bytes),
+ .bytes => |bytes| try code.appendSlice(bytes.toSlice(array_type.lenIncludingSentinel(), ip)),
.elems, .repeated_elem => {
var index: u64 = 0;
- const len_including_sentinel =
- array_type.len + @intFromBool(array_type.sentinel != .none);
- while (index < len_including_sentinel) : (index += 1) {
+ while (index < array_type.lenIncludingSentinel()) : (index += 1) {
switch (try generateSymbol(bin_file, src_loc, Value.fromInterned(switch (aggregate.storage) {
.bytes => unreachable,
- .elems => |elems| elems[@as(usize, @intCast(index))],
+ .elems => |elems| elems[@intCast(index)],
.repeated_elem => |elem| if (index < array_type.len)
elem
else
@@ -399,7 +397,7 @@ pub fn generateSymbol(
}) {
.bool_true => true,
.bool_false => false,
- else => |elem| switch (mod.intern_pool.indexToKey(elem)) {
+ else => |elem| switch (ip.indexToKey(elem)) {
.undef => continue,
.int => |int| switch (int.storage) {
.u64 => |x| switch (x) {
@@ -420,7 +418,7 @@ pub fn generateSymbol(
}
} else {
switch (aggregate.storage) {
- .bytes => |bytes| try code.appendSlice(bytes),
+ .bytes => |bytes| try code.appendSlice(bytes.toSlice(vector_type.len, ip)),
.elems, .repeated_elem => {
var index: u64 = 0;
while (index < vector_type.len) : (index += 1) {
@@ -457,7 +455,7 @@ pub fn generateSymbol(
const field_val = switch (aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field_ty,
- .storage = .{ .u64 = bytes[index] },
+ .storage = .{ .u64 = bytes.at(index, ip) },
} }),
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
@@ -493,7 +491,7 @@ pub fn generateSymbol(
const field_val = switch (aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field_ty,
- .storage = .{ .u64 = bytes[index] },
+ .storage = .{ .u64 = bytes.at(index, ip) },
} }),
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
@@ -513,7 +511,7 @@ pub fn generateSymbol(
} else {
Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), mod, code.items[current_pos..], bits) catch unreachable;
}
- bits += @as(u16, @intCast(Type.fromInterned(field_ty).bitSize(mod)));
+ bits += @intCast(Type.fromInterned(field_ty).bitSize(mod));
}
},
.auto, .@"extern" => {
@@ -529,7 +527,7 @@ pub fn generateSymbol(
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
.ty = field_ty,
- .storage = .{ .u64 = bytes[field_index] },
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
} }),
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
@@ -625,7 +623,8 @@ fn lowerParentPtr(
reloc_info: RelocInfo,
) CodeGenError!Result {
const mod = bin_file.comp.module.?;
- const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
+ const ip = &mod.intern_pool;
+ const ptr = ip.indexToKey(parent_ptr).ptr;
return switch (ptr.addr) {
.decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
.anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
@@ -636,10 +635,10 @@ fn lowerParentPtr(
eu_payload,
code,
debug_output,
- reloc_info.offset(@as(u32, @intCast(errUnionPayloadOffset(
- Type.fromInterned(mod.intern_pool.typeOf(eu_payload)),
+ reloc_info.offset(@intCast(errUnionPayloadOffset(
+ Type.fromInterned(ip.typeOf(eu_payload)),
mod,
- )))),
+ ))),
),
.opt_payload => |opt_payload| try lowerParentPtr(
bin_file,
@@ -655,19 +654,19 @@ fn lowerParentPtr(
elem.base,
code,
debug_output,
- reloc_info.offset(@as(u32, @intCast(elem.index *
- Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod).abiSize(mod)))),
+ reloc_info.offset(@intCast(elem.index *
+ Type.fromInterned(ip.typeOf(elem.base)).elemType2(mod).abiSize(mod))),
),
.field => |field| {
- const base_ptr_ty = mod.intern_pool.typeOf(field.base);
- const base_ty = mod.intern_pool.indexToKey(base_ptr_ty).ptr_type.child;
+ const base_ptr_ty = ip.typeOf(field.base);
+ const base_ty = ip.indexToKey(base_ptr_ty).ptr_type.child;
return lowerParentPtr(
bin_file,
src_loc,
field.base,
code,
debug_output,
- reloc_info.offset(switch (mod.intern_pool.indexToKey(base_ty)) {
+ reloc_info.offset(switch (ip.indexToKey(base_ty)) {
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.One, .Many, .C => unreachable,
.Slice => switch (field.index) {
@@ -723,11 +722,12 @@ fn lowerAnonDeclRef(
) CodeGenError!Result {
_ = debug_output;
const zcu = lf.comp.module.?;
+ const ip = &zcu.intern_pool;
const target = lf.comp.root_mod.resolved_target.result;
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
const decl_val = anon_decl.val;
- const decl_ty = Type.fromInterned(zcu.intern_pool.typeOf(decl_val));
+ const decl_ty = Type.fromInterned(ip.typeOf(decl_val));
log.debug("lowerAnonDecl: ty = {}", .{decl_ty.fmt(zcu)});
const is_fn_body = decl_ty.zigTypeTag(zcu) == .Fn;
if (!is_fn_body and !decl_ty.hasRuntimeBits(zcu)) {
@@ -735,7 +735,7 @@ fn lowerAnonDeclRef(
return Result.ok;
}
- const decl_align = zcu.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
+ const decl_align = ip.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
const res = try lf.lowerAnonDecl(decl_val, decl_align, src_loc);
switch (res) {
.ok => {},
@@ -787,8 +787,8 @@ fn lowerDeclRef(
});
const endian = target.cpu.arch.endian();
switch (ptr_width) {
- 16 => mem.writeInt(u16, try code.addManyAsArray(2), @as(u16, @intCast(vaddr)), endian),
- 32 => mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(vaddr)), endian),
+ 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(vaddr), endian),
+ 32 => mem.writeInt(u32, try code.addManyAsArray(4), @intCast(vaddr), endian),
64 => mem.writeInt(u64, try code.addManyAsArray(8), vaddr, endian),
else => unreachable,
}
@@ -859,6 +859,7 @@ fn genDeclRef(
ptr_decl_index: InternPool.DeclIndex,
) CodeGenError!GenResult {
const zcu = lf.comp.module.?;
+ const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
log.debug("genDeclRef: val = {}", .{val.fmtValue(zcu)});
@@ -869,7 +870,7 @@ fn genDeclRef(
const ptr_bits = target.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
- const decl_index = switch (zcu.intern_pool.indexToKey(ptr_decl.val.toIntern())) {
+ const decl_index = switch (ip.indexToKey(ptr_decl.val.toIntern())) {
.func => |func| func.owner_decl,
.extern_func => |extern_func| extern_func.decl,
else => ptr_decl_index,
@@ -909,12 +910,9 @@ fn genDeclRef(
if (lf.cast(link.File.Elf)) |elf_file| {
if (is_extern) {
- const name = zcu.intern_pool.stringToSlice(decl.name);
+ const name = decl.name.toSlice(ip);
// TODO audit this
- const lib_name = if (decl.getOwnedVariable(zcu)) |ov|
- zcu.intern_pool.stringToSliceUnwrap(ov.lib_name)
- else
- null;
+ const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
@@ -927,11 +925,8 @@ fn genDeclRef(
return GenResult.mcv(.{ .load_symbol = sym.esym_index });
} else if (lf.cast(link.File.MachO)) |macho_file| {
if (is_extern) {
- const name = zcu.intern_pool.stringToSlice(decl.name);
- const lib_name = if (decl.getOwnedVariable(zcu)) |ov|
- zcu.intern_pool.stringToSliceUnwrap(ov.lib_name)
- else
- null;
+ const name = decl.name.toSlice(ip);
+ const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
macho_file.getSymbol(macho_file.getZigObject().?.symbols.items[sym_index]).flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
@@ -944,12 +939,9 @@ fn genDeclRef(
return GenResult.mcv(.{ .load_symbol = sym.nlist_idx });
} else if (lf.cast(link.File.Coff)) |coff_file| {
if (is_extern) {
- const name = zcu.intern_pool.stringToSlice(decl.name);
+ const name = decl.name.toSlice(ip);
// TODO audit this
- const lib_name = if (decl.getOwnedVariable(zcu)) |ov|
- zcu.intern_pool.stringToSliceUnwrap(ov.lib_name)
- else
- null;
+ const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const global_index = try coff_file.getGlobalSymbol(name, lib_name);
try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index });
@@ -1012,6 +1004,7 @@ pub fn genTypedValue(
owner_decl_index: InternPool.DeclIndex,
) CodeGenError!GenResult {
const zcu = lf.comp.module.?;
+ const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
log.debug("genTypedValue: val = {}", .{val.fmtValue(zcu)});
@@ -1024,7 +1017,7 @@ pub fn genTypedValue(
const target = namespace.file_scope.mod.resolved_target.result;
const ptr_bits = target.ptrBitWidth();
- if (!ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(val.toIntern())) {
+ if (!ty.isSlice(zcu)) switch (ip.indexToKey(val.toIntern())) {
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| return genDeclRef(lf, src_loc, val, decl),
else => {},
@@ -1041,7 +1034,7 @@ pub fn genTypedValue(
return GenResult.mcv(.{ .immediate = 0 });
},
.none => {},
- else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
+ else => switch (ip.indexToKey(val.toIntern())) {
.int => {
return GenResult.mcv(.{ .immediate = val.toUnsignedInt(zcu) });
},
@@ -1052,8 +1045,8 @@ pub fn genTypedValue(
.Int => {
const info = ty.intInfo(zcu);
if (info.bits <= ptr_bits) {
- const unsigned = switch (info.signedness) {
- .signed => @as(u64, @bitCast(val.toSignedInt(zcu))),
+ const unsigned: u64 = switch (info.signedness) {
+ .signed => @bitCast(val.toSignedInt(zcu)),
.unsigned => val.toUnsignedInt(zcu),
};
return GenResult.mcv(.{ .immediate = unsigned });
@@ -1075,7 +1068,7 @@ pub fn genTypedValue(
}
},
.Enum => {
- const enum_tag = zcu.intern_pool.indexToKey(val.toIntern()).enum_tag;
+ const enum_tag = ip.indexToKey(val.toIntern()).enum_tag;
return genTypedValue(
lf,
src_loc,
@@ -1084,7 +1077,7 @@ pub fn genTypedValue(
);
},
.ErrorSet => {
- const err_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name;
+ const err_name = ip.indexToKey(val.toIntern()).err.name;
const error_index = zcu.global_error_set.getIndex(err_name).?;
return GenResult.mcv(.{ .immediate = error_index });
},
@@ -1094,7 +1087,7 @@ pub fn genTypedValue(
if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
// We use the error type directly as the type.
const err_int_ty = try zcu.errorIntType();
- switch (zcu.intern_pool.indexToKey(val.toIntern()).error_union.val) {
+ switch (ip.indexToKey(val.toIntern()).error_union.val) {
.err_name => |err_name| return genTypedValue(
lf,
src_loc,
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 95f4ecc4ac..818267a8b8 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -43,10 +43,12 @@ pub const CValue = union(enum) {
decl_ref: InternPool.DeclIndex,
/// An undefined value (cannot be dereferenced)
undef: Type,
- /// Render the slice as an identifier (using fmtIdent)
+ /// Rendered as an identifier (using fmtIdent)
identifier: []const u8,
- /// Render the slice as an payload.identifier (using fmtIdent)
+ /// Rendered as "payload." followed by as identifier (using fmtIdent)
payload_identifier: []const u8,
+ /// Rendered with fmtCTypePoolString
+ ctype_pool_string: CType.Pool.String,
};
const BlockData = struct {
@@ -62,10 +64,10 @@ pub const LazyFnKey = union(enum) {
never_inline: InternPool.DeclIndex,
};
pub const LazyFnValue = struct {
- fn_name: CType.String,
+ fn_name: CType.Pool.String,
data: Data,
- pub const Data = union {
+ const Data = union {
tag_name: Type,
never_tail: void,
never_inline: void,
@@ -80,7 +82,7 @@ const Local = struct {
_: u20 = undefined,
},
- pub fn getType(local: Local) LocalType {
+ fn getType(local: Local) LocalType {
return .{ .ctype = local.ctype, .alignas = local.flags.alignas };
}
};
@@ -96,12 +98,20 @@ const ValueRenderLocation = enum {
StaticInitializer,
Other,
- pub fn isInitializer(self: ValueRenderLocation) bool {
- return switch (self) {
+ fn isInitializer(loc: ValueRenderLocation) bool {
+ return switch (loc) {
.Initializer, .StaticInitializer => true,
else => false,
};
}
+
+ fn toCTypeKind(loc: ValueRenderLocation) CType.Kind {
+ return switch (loc) {
+ .FunctionArgument => .parameter,
+ .Initializer, .Other => .complete,
+ .StaticInitializer => .global,
+ };
+ }
};
const BuiltinInfo = enum { none, bits };
@@ -234,12 +244,11 @@ fn isReservedIdent(ident: []const u8) bool {
fn formatIdent(
ident: []const u8,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
+ comptime fmt_str: []const u8,
+ _: std.fmt.FormatOptions,
writer: anytype,
-) !void {
- _ = options;
- const solo = fmt.len != 0 and fmt[0] == ' '; // space means solo; not part of a bigger ident.
+) @TypeOf(writer).Error!void {
+ const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
if (solo and isReservedIdent(ident)) {
try writer.writeAll("zig_e_");
}
@@ -256,11 +265,32 @@ fn formatIdent(
}
}
}
-
pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
return .{ .data = ident };
}
+const CTypePoolStringFormatData = struct {
+ ctype_pool_string: CType.Pool.String,
+ ctype_pool: *const CType.Pool,
+};
+fn formatCTypePoolString(
+ data: CTypePoolStringFormatData,
+ comptime fmt_str: []const u8,
+ fmt_opts: std.fmt.FormatOptions,
+ writer: anytype,
+) @TypeOf(writer).Error!void {
+ if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
+ try formatIdent(slice, fmt_str, fmt_opts, writer)
+ else
+ try writer.print("{}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
+}
+pub fn fmtCTypePoolString(
+ ctype_pool_string: CType.Pool.String,
+ ctype_pool: *const CType.Pool,
+) std.fmt.Formatter(formatCTypePoolString) {
+ return .{ .data = .{ .ctype_pool_string = ctype_pool_string, .ctype_pool = ctype_pool } };
+}
+
// Returns true if `formatIdent` would make any edits to ident.
// This must be kept in sync with `formatIdent`.
pub fn isMangledIdent(ident: []const u8, solo: bool) bool {
@@ -321,7 +351,7 @@ pub const Function = struct {
try writer.writeAll(" = ");
try f.object.dg.renderValue(writer, val, .StaticInitializer);
try writer.writeAll(";\n ");
- break :result decl_c_value;
+ break :result .{ .local = decl_c_value.new_local };
} else .{ .constant = val };
gop.value_ptr.* = result;
@@ -377,27 +407,7 @@ pub const Function = struct {
switch (c_value) {
.none => unreachable,
.new_local, .local => |i| try w.print("t{d}", .{i}),
- .local_ref => |i| {
- const local = &f.locals.items[i];
- if (local.flags.alignas.abiOrder().compare(.lt)) {
- const gpa = f.object.dg.gpa;
- const mod = f.object.dg.mod;
- const ctype_pool = &f.object.dg.ctype_pool;
-
- try w.writeByte('(');
- try f.renderCType(w, try ctype_pool.getPointer(gpa, .{
- .elem_ctype = try ctype_pool.fromIntInfo(gpa, .{
- .signedness = .unsigned,
- .bits = @min(
- local.flags.alignas.toByteUnits(),
- mod.resolved_target.result.maxIntAlignment(),
- ) * 8,
- }, mod, .forward),
- }));
- try w.writeByte(')');
- }
- try w.print("&t{d}", .{i});
- },
+ .local_ref => |i| try w.print("&t{d}", .{i}),
.constant => |val| try f.object.dg.renderValue(w, val, location),
.arg => |i| try w.print("a{d}", .{i}),
.arg_array => |i| try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
@@ -505,7 +515,7 @@ pub const Function = struct {
.never_inline,
=> |owner_decl| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
@tagName(key),
- fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
+ fmtIdent(zcu.declPtr(owner_decl).name.toSlice(&zcu.intern_pool)),
@intFromEnum(owner_decl),
}),
},
@@ -516,7 +526,7 @@ pub const Function = struct {
},
};
}
- return gop.value_ptr.fn_name.slice(ctype_pool);
+ return gop.value_ptr.fn_name.toSlice(ctype_pool).?;
}
pub fn deinit(f: *Function) void {
@@ -538,6 +548,43 @@ pub const Function = struct {
const zcu = f.object.dg.zcu;
return f.air.typeOfIndex(inst, &zcu.intern_pool);
}
+
+ fn copyCValue(f: *Function, ctype: CType, dst: CValue, src: CValue) !void {
+ switch (dst) {
+ .new_local, .local => |dst_local_index| switch (src) {
+ .new_local, .local => |src_local_index| if (dst_local_index == src_local_index) return,
+ else => {},
+ },
+ else => {},
+ }
+ const writer = f.object.writer();
+ const a = try Assignment.start(f, writer, ctype);
+ try f.writeCValue(writer, dst, .Other);
+ try a.assign(f, writer);
+ try f.writeCValue(writer, src, .Initializer);
+ try a.end(f, writer);
+ }
+
+ fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue {
+ switch (src) {
+ // Move the freshly allocated local to be owned by this instruction,
+ // by returning it here instead of freeing it.
+ .new_local => return src,
+ else => {
+ try freeCValue(f, inst, src);
+ const dst = try f.allocLocal(inst, ty);
+ try f.copyCValue(try f.ctypeFromType(ty, .complete), dst, src);
+ return dst;
+ },
+ }
+ }
+
+ fn freeCValue(f: *Function, inst: ?Air.Inst.Index, val: CValue) !void {
+ switch (val) {
+ .new_local => |local_index| try freeLocal(f, inst, local_index, null),
+ else => {},
+ }
+ }
};
/// This data is available when outputting .c code for a `Zcu`.
@@ -627,13 +674,14 @@ pub const DeclGen = struct {
// them). The analysis until now should ensure that the C function
// pointers are compatible. If they are not, then there is a bug
// somewhere and we should let the C compiler tell us about it.
- const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype;
+ const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
+ const elem_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
const need_cast = !elem_ctype.eql(decl_ctype) and
(elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
- try dg.renderType(writer, ptr_ty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeByte('&');
@@ -692,13 +740,14 @@ pub const DeclGen = struct {
// them). The analysis until now should ensure that the C function
// pointers are compatible. If they are not, then there is a bug
// somewhere and we should let the C compiler tell us about it.
- const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype;
+ const ctype = try dg.ctypeFromType(ty, .complete);
+ const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
const need_cast = !elem_ctype.eql(decl_ctype) and
(elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
try writer.writeByte('&');
@@ -822,25 +871,18 @@ pub const DeclGen = struct {
try dg.fmtIntLiteral(try zcu.intValue(Type.usize, byte_offset), .Other),
});
},
- .end => {
- const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
- if (!ptr_ctype.eql(ptr_base_ctype)) {
- try writer.writeByte('(');
- try dg.renderCType(writer, ptr_ctype);
- try writer.writeByte(')');
- }
- try writer.writeAll("((");
- try dg.renderParentPtr(writer, field.base, location);
- try writer.print(") + {})", .{
- try dg.fmtIntLiteral(try zcu.intValue(Type.usize, 1), .Other),
- });
- },
}
},
.comptime_field, .comptime_alloc => unreachable,
}
}
+ fn renderErrorName(dg: *DeclGen, writer: anytype, err_name: InternPool.NullTerminatedString) !void {
+ const zcu = dg.zcu;
+ const ip = &zcu.intern_pool;
+ try writer.print("zig_error_{}", .{fmtIdent(err_name.toSlice(ip))});
+ }
+
fn renderValue(
dg: *DeclGen,
writer: anytype,
@@ -850,6 +892,7 @@ pub const DeclGen = struct {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
const target = &dg.mod.resolved_target.result;
+ const ctype_pool = &dg.ctype_pool;
const initializer_type: ValueRenderLocation = switch (location) {
.StaticInitializer => .StaticInitializer,
@@ -858,6 +901,7 @@ pub const DeclGen = struct {
const ty = val.typeOf(zcu);
if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);
+ const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
switch (ip.indexToKey(val.toIntern())) {
// types, not values
.int_type,
@@ -903,76 +947,53 @@ pub const DeclGen = struct {
.u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}),
.lazy_align, .lazy_size => {
try writer.writeAll("((");
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.print("){x})", .{try dg.fmtIntLiteral(
try zcu.intValue(Type.usize, val.toUnsignedInt(zcu)),
.Other,
)});
},
},
- .err => |err| try writer.print("zig_error_{}", .{
- fmtIdent(ip.stringToSlice(err.name)),
- }),
- .error_union => |error_union| {
- const payload_ty = ty.errorUnionPayload(zcu);
- const error_ty = ty.errorUnionSet(zcu);
- const err_int_ty = try zcu.errorIntType();
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- switch (error_union.val) {
- .err_name => |err_name| return dg.renderValue(
- writer,
- Value.fromInterned((try zcu.intern(.{ .err = .{
- .ty = error_ty.toIntern(),
- .name = err_name,
- } }))),
- location,
- ),
- .payload => return dg.renderValue(
- writer,
- try zcu.intValue(err_int_ty, 0),
- location,
- ),
+ .err => |err| try dg.renderErrorName(writer, err.name),
+ .error_union => |error_union| switch (ctype.info(ctype_pool)) {
+ .basic => switch (error_union.val) {
+ .err_name => |err_name| try dg.renderErrorName(writer, err_name),
+ .payload => try writer.writeAll("0"),
+ },
+ .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderCType(writer, ctype);
+ try writer.writeByte(')');
}
- }
-
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
-
- try writer.writeAll("{ .payload = ");
- try dg.renderValue(
- writer,
- Value.fromInterned(switch (error_union.val) {
- .err_name => (try zcu.undefValue(payload_ty)).toIntern(),
- .payload => |payload| payload,
- }),
- initializer_type,
- );
- try writer.writeAll(", .error = ");
- switch (error_union.val) {
- .err_name => |err_name| try dg.renderValue(
- writer,
- Value.fromInterned((try zcu.intern(.{ .err = .{
- .ty = error_ty.toIntern(),
- .name = err_name,
- } }))),
- location,
- ),
- .payload => try dg.renderValue(
- writer,
- try zcu.intValue(err_int_ty, 0),
- location,
- ),
- }
- try writer.writeAll(" }");
+ try writer.writeByte('{');
+ for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeByte(',');
+ switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
+ .@"error" => switch (error_union.val) {
+ .err_name => |err_name| try dg.renderErrorName(writer, err_name),
+ .payload => try writer.writeByte('0'),
+ },
+ .payload => switch (error_union.val) {
+ .err_name => try dg.renderUndefValue(
+ writer,
+ ty.errorUnionPayload(zcu),
+ initializer_type,
+ ),
+ .payload => |payload| try dg.renderValue(
+ writer,
+ Value.fromInterned(payload),
+ initializer_type,
+ ),
+ },
+ else => unreachable,
+ }
+ }
+ try writer.writeByte('}');
+ },
},
- .enum_tag => |enum_tag| try dg.renderValue(
- writer,
- Value.fromInterned(enum_tag.int),
- location,
- ),
+ .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location),
.float => {
const bits = ty.floatBits(target.*);
const f128_val = val.toFloat(f128, zcu);
@@ -1063,15 +1084,23 @@ pub const DeclGen = struct {
if (!empty) try writer.writeByte(')');
},
.slice => |slice| {
+ const aggregate = ctype.info(ctype_pool).aggregate;
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
try writer.writeByte('{');
- try dg.renderValue(writer, Value.fromInterned(slice.ptr), initializer_type);
- try writer.writeAll(", ");
- try dg.renderValue(writer, Value.fromInterned(slice.len), initializer_type);
+ for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeByte(',');
+ try dg.renderValue(writer, Value.fromInterned(
+ switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
+ .ptr => slice.ptr,
+ .len => slice.len,
+ else => unreachable,
+ },
+ ), initializer_type);
+ }
try writer.writeByte('}');
},
.ptr => |ptr| switch (ptr.addr) {
@@ -1079,7 +1108,7 @@ pub const DeclGen = struct {
.anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location),
.int => |int| {
try writer.writeAll("((");
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.print("){x})", .{try dg.fmtIntLiteral(Value.fromInterned(int), location)});
},
.eu_payload,
@@ -1089,54 +1118,80 @@ pub const DeclGen = struct {
=> try dg.renderParentPtr(writer, val.toIntern(), location),
.comptime_field, .comptime_alloc => unreachable,
},
- .opt => |opt| {
- const payload_ty = ty.optionalChild(zcu);
-
- const is_null_val = Value.makeBool(opt.val == .none);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
- return dg.renderValue(writer, is_null_val, location);
-
- if (ty.optionalReprIsPayload(zcu)) return dg.renderValue(
- writer,
+ .opt => |opt| switch (ctype.info(ctype_pool)) {
+ .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
+ .none => "true",
+ else => "false",
+ }) else switch (opt.val) {
+ .none => try writer.writeAll("0"),
+ else => |payload| switch (ip.indexToKey(payload)) {
+ .undef => |err_ty| try dg.renderUndefValue(
+ writer,
+ Type.fromInterned(err_ty),
+ location,
+ ),
+ .err => |err| try dg.renderErrorName(writer, err.name),
+ else => unreachable,
+ },
+ },
+ .pointer => switch (opt.val) {
+ .none => try writer.writeAll("NULL"),
+ else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),
+ },
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| {
switch (opt.val) {
- .none => switch (payload_ty.zigTypeTag(zcu)) {
- .ErrorSet => try zcu.intValue(try zcu.errorIntType(), 0),
- .Pointer => try zcu.getCoerced(val, payload_ty),
+ .none => {},
+ else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
+ .is_null, .payload => {},
+ .ptr, .len => return dg.renderValue(
+ writer,
+ Value.fromInterned(payload),
+ location,
+ ),
else => unreachable,
},
- else => |payload| Value.fromInterned(payload),
- },
- location,
- );
-
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
-
- try writer.writeAll("{ .payload = ");
- switch (opt.val) {
- .none => try dg.renderUndefValue(writer, payload_ty, initializer_type),
- else => |payload| try dg.renderValue(
- writer,
- Value.fromInterned(payload),
- initializer_type,
- ),
- }
- try writer.writeAll(", .is_null = ");
- try dg.renderValue(writer, is_null_val, initializer_type);
- try writer.writeAll(" }");
+ }
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderCType(writer, ctype);
+ try writer.writeByte(')');
+ }
+ try writer.writeByte('{');
+ for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeByte(',');
+ switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
+ .is_null => try writer.writeAll(switch (opt.val) {
+ .none => "true",
+ else => "false",
+ }),
+ .payload => switch (opt.val) {
+ .none => try dg.renderUndefValue(
+ writer,
+ ty.optionalChild(zcu),
+ initializer_type,
+ ),
+ else => |payload| try dg.renderValue(
+ writer,
+ Value.fromInterned(payload),
+ initializer_type,
+ ),
+ },
+ .ptr => try writer.writeAll("NULL"),
+ .len => try dg.renderUndefValue(writer, Type.usize, initializer_type),
+ else => unreachable,
+ }
+ }
+ try writer.writeByte('}');
+ },
},
.aggregate => switch (ip.indexToKey(ty.toIntern())) {
.array_type, .vector_type => {
if (location == .FunctionArgument) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
- // Fall back to generic implementation.
-
const ai = ty.arrayInfo(zcu);
if (ai.elem_type.eql(Type.u8, zcu)) {
var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu));
@@ -1173,7 +1228,7 @@ pub const DeclGen = struct {
.anon_struct_type => |tuple| {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1191,7 +1246,7 @@ pub const DeclGen = struct {
switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
.ty = field_ty.toIntern(),
- .storage = .{ .u64 = bytes[field_index] },
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
} }),
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
@@ -1209,7 +1264,7 @@ pub const DeclGen = struct {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1225,7 +1280,7 @@ pub const DeclGen = struct {
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
.ty = field_ty.toIntern(),
- .storage = .{ .u64 = bytes[field_index] },
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
} }),
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
@@ -1251,7 +1306,7 @@ pub const DeclGen = struct {
if (eff_num_fields == 0) {
try writer.writeByte('(');
- try dg.renderUndefValue(writer, ty, initializer_type);
+ try dg.renderUndefValue(writer, ty, location);
try writer.writeByte(')');
} else if (ty.bitSize(zcu) > 64) {
// zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
@@ -1271,7 +1326,7 @@ pub const DeclGen = struct {
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
.ty = field_ty.toIntern(),
- .storage = .{ .u64 = bytes[field_index] },
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
} }),
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
@@ -1306,13 +1361,13 @@ pub const DeclGen = struct {
if (!empty) try writer.writeAll(" | ");
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
.ty = field_ty.toIntern(),
- .storage = .{ .u64 = bytes[field_index] },
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
} }),
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
@@ -1347,7 +1402,7 @@ pub const DeclGen = struct {
try dg.renderType(writer, backing_ty);
try writer.writeByte(')');
}
- try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
+ try dg.renderValue(writer, Value.fromInterned(un.val), location);
},
.@"extern" => {
if (location == .StaticInitializer) {
@@ -1360,7 +1415,7 @@ pub const DeclGen = struct {
try writer.writeAll(")(");
try dg.renderType(writer, backing_ty);
try writer.writeAll("){");
- try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
+ try dg.renderValue(writer, Value.fromInterned(un.val), location);
try writer.writeAll("})");
},
else => unreachable,
@@ -1368,7 +1423,7 @@ pub const DeclGen = struct {
} else {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1379,43 +1434,56 @@ pub const DeclGen = struct {
if (field_ty.hasRuntimeBits(zcu)) {
if (field_ty.isPtrAtRuntime(zcu)) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
} else if (field_ty.zigTypeTag(zcu) == .Float) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
- try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
- } else {
- try writer.writeAll("0");
- }
+ try dg.renderValue(writer, Value.fromInterned(un.val), location);
+ } else try writer.writeAll("0");
return;
}
- try writer.writeByte('{');
- if (ty.unionTagTypeSafety(zcu)) |_| {
- const layout = zcu.getUnionLayout(loaded_union);
- if (layout.tag_size != 0) {
- try writer.writeAll(" .tag = ");
- try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);
+ const has_tag = loaded_union.hasTag(ip);
+ if (has_tag) try writer.writeByte('{');
+ const aggregate = ctype.info(ctype_pool).aggregate;
+ for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
+ if (outer_field_index > 0) try writer.writeByte(',');
+ switch (if (has_tag)
+ aggregate.fields.at(outer_field_index, ctype_pool).name.index
+ else
+ .payload) {
+ .tag => try dg.renderValue(
+ writer,
+ Value.fromInterned(un.tag),
+ initializer_type,
+ ),
+ .payload => {
+ try writer.writeByte('{');
+ if (field_ty.hasRuntimeBits(zcu)) {
+ try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))});
+ try dg.renderValue(
+ writer,
+ Value.fromInterned(un.val),
+ initializer_type,
+ );
+ try writer.writeByte(' ');
+ } else for (0..loaded_union.field_types.len) |inner_field_index| {
+ const inner_field_ty = Type.fromInterned(
+ loaded_union.field_types.get(ip)[inner_field_index],
+ );
+ if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
+ try dg.renderUndefValue(writer, inner_field_ty, initializer_type);
+ break;
+ }
+ try writer.writeByte('}');
+ },
+ else => unreachable,
}
- if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
- if (layout.tag_size != 0) try writer.writeByte(',');
- try writer.writeAll(" .payload = {");
- }
- if (field_ty.hasRuntimeBits(zcu)) {
- try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
- try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
- try writer.writeByte(' ');
- } else for (0..loaded_union.field_types.len) |this_field_index| {
- const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]);
- if (!this_field_ty.hasRuntimeBits(zcu)) continue;
- try dg.renderUndefValue(writer, this_field_ty, initializer_type);
- break;
}
- if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
- try writer.writeByte('}');
+ if (has_tag) try writer.writeByte('}');
}
},
}
@@ -1430,6 +1498,7 @@ pub const DeclGen = struct {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
const target = &dg.mod.resolved_target.result;
+ const ctype_pool = &dg.ctype_pool;
const initializer_type: ValueRenderLocation = switch (location) {
.StaticInitializer => .StaticInitializer,
@@ -1441,6 +1510,7 @@ pub const DeclGen = struct {
.ReleaseFast, .ReleaseSmall => false,
};
+ const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
switch (ty.toIntern()) {
.c_longdouble_type,
.f16_type,
@@ -1478,48 +1548,64 @@ pub const DeclGen = struct {
=> return writer.print("{x}", .{
try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
}),
- .ptr_type => if (ty.isSlice(zcu)) {
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .One, .Many, .C => {
+ try writer.writeAll("((");
+ try dg.renderCType(writer, ctype);
+ return writer.print("){x})", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
+ });
+ },
+ .Slice => {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderCType(writer, ctype);
+ try writer.writeByte(')');
+ }
- try writer.writeAll("{(");
- const ptr_ty = ty.slicePtrFieldType(zcu);
- try dg.renderType(writer, ptr_ty);
- return writer.print("){x}, {0x}}}", .{
- try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
- });
- } else {
- try writer.writeAll("((");
- try dg.renderType(writer, ty);
- return writer.print("){x})", .{
- try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
- });
+ try writer.writeAll("{(");
+ const ptr_ty = ty.slicePtrFieldType(zcu);
+ try dg.renderType(writer, ptr_ty);
+ return writer.print("){x}, {0x}}}", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
+ });
+ },
},
- .opt_type => {
- const payload_ty = ty.optionalChild(zcu);
-
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return dg.renderUndefValue(writer, Type.bool, location);
- }
-
- if (ty.optionalReprIsPayload(zcu)) {
- return dg.renderUndefValue(writer, payload_ty, location);
- }
-
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
-
- try writer.writeAll("{ .payload = ");
- try dg.renderUndefValue(writer, payload_ty, initializer_type);
- try writer.writeAll(", .is_null = ");
- try dg.renderUndefValue(writer, Type.bool, initializer_type);
- return writer.writeAll(" }");
+ .opt_type => |child_type| switch (ctype.info(ctype_pool)) {
+ .basic, .pointer => try dg.renderUndefValue(
+ writer,
+ Type.fromInterned(if (ctype.isBool()) .bool_type else child_type),
+ location,
+ ),
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| {
+ switch (aggregate.fields.at(0, ctype_pool).name.index) {
+ .is_null, .payload => {},
+ .ptr, .len => return dg.renderUndefValue(
+ writer,
+ Type.fromInterned(child_type),
+ location,
+ ),
+ else => unreachable,
+ }
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderCType(writer, ctype);
+ try writer.writeByte(')');
+ }
+ try writer.writeByte('{');
+ for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeByte(',');
+ try dg.renderUndefValue(writer, Type.fromInterned(
+ switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
+ .is_null => .bool_type,
+ .payload => child_type,
+ else => unreachable,
+ },
+ ), initializer_type);
+ }
+ try writer.writeByte('}');
+ },
},
.struct_type => {
const loaded_struct = ip.loadStructType(ty.toIntern());
@@ -1527,7 +1613,7 @@ pub const DeclGen = struct {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1552,7 +1638,7 @@ pub const DeclGen = struct {
.anon_struct_type => |anon_struct_info| {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1575,54 +1661,80 @@ pub const DeclGen = struct {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
- try writer.writeByte('{');
- if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
- const layout = ty.unionGetLayout(zcu);
- if (layout.tag_size != 0) {
- try writer.writeAll(" .tag = ");
- try dg.renderUndefValue(writer, tag_ty, initializer_type);
+ const has_tag = loaded_union.hasTag(ip);
+ if (has_tag) try writer.writeByte('{');
+ const aggregate = ctype.info(ctype_pool).aggregate;
+ for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
+ if (outer_field_index > 0) try writer.writeByte(',');
+ switch (if (has_tag)
+ aggregate.fields.at(outer_field_index, ctype_pool).name.index
+ else
+ .payload) {
+ .tag => try dg.renderUndefValue(
+ writer,
+ Type.fromInterned(loaded_union.enum_tag_ty),
+ initializer_type,
+ ),
+ .payload => {
+ try writer.writeByte('{');
+ for (0..loaded_union.field_types.len) |inner_field_index| {
+ const inner_field_ty = Type.fromInterned(
+ loaded_union.field_types.get(ip)[inner_field_index],
+ );
+ if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
+ try dg.renderUndefValue(
+ writer,
+ inner_field_ty,
+ initializer_type,
+ );
+ break;
+ }
+ try writer.writeByte('}');
+ },
+ else => unreachable,
}
- if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
- if (layout.tag_size != 0) try writer.writeByte(',');
- try writer.writeAll(" .payload = {");
}
- for (0..loaded_union.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBits(zcu)) continue;
- try dg.renderUndefValue(writer, field_ty, initializer_type);
- break;
- }
- if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
- return writer.writeByte('}');
+ if (has_tag) try writer.writeByte('}');
},
.@"packed" => return writer.print("{x}", .{
try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
}),
}
},
- .error_union_type => {
- const payload_ty = ty.errorUnionPayload(zcu);
- const error_ty = ty.errorUnionSet(zcu);
-
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return dg.renderUndefValue(writer, error_ty, location);
- }
-
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
-
- try writer.writeAll("{ .payload = ");
- try dg.renderUndefValue(writer, payload_ty, initializer_type);
- try writer.writeAll(", .error = ");
- try dg.renderUndefValue(writer, error_ty, initializer_type);
- return writer.writeAll(" }");
+ .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) {
+ .basic => try dg.renderUndefValue(
+ writer,
+ Type.fromInterned(error_union_type.error_set_type),
+ location,
+ ),
+ .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderCType(writer, ctype);
+ try writer.writeByte(')');
+ }
+ try writer.writeByte('{');
+ for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeByte(',');
+ try dg.renderUndefValue(
+ writer,
+ Type.fromInterned(
+ switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
+ .@"error" => error_union_type.error_set_type,
+ .payload => error_union_type.payload_type,
+ else => unreachable,
+ },
+ ),
+ initializer_type,
+ );
+ }
+ try writer.writeByte('}');
+ },
},
.array_type, .vector_type => {
const ai = ty.arrayInfo(zcu);
@@ -1637,7 +1749,7 @@ pub const DeclGen = struct {
} else {
if (!location.isInitializer()) {
try writer.writeByte('(');
- try dg.renderType(writer, ty);
+ try dg.renderCType(writer, ctype);
try writer.writeByte(')');
}
@@ -1687,6 +1799,7 @@ pub const DeclGen = struct {
name: union(enum) {
export_index: u32,
ident: []const u8,
+ fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
},
) !void {
const zcu = dg.zcu;
@@ -1730,6 +1843,7 @@ pub const DeclGen = struct {
try dg.renderDeclName(w, fn_decl_index, export_index);
},
.ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }),
+ .fmt_ctype_pool_string => |fmt| try w.print("{}{ }", .{ trailing, fmt }),
}
try renderTypeSuffix(
@@ -1754,14 +1868,12 @@ pub const DeclGen = struct {
switch (name) {
.export_index => |export_index| mangled: {
const maybe_exports = zcu.decl_exports.get(fn_decl_index);
- const external_name = ip.stringToSlice(
- if (maybe_exports) |exports|
- exports.items[export_index].opts.name
- else if (fn_decl.isExtern(zcu))
- fn_decl.name
- else
- break :mangled,
- );
+ const external_name = (if (maybe_exports) |exports|
+ exports.items[export_index].opts.name
+ else if (fn_decl.isExtern(zcu))
+ fn_decl.name
+ else
+ break :mangled).toSlice(ip);
const is_mangled = isMangledIdent(external_name, true);
const is_export = export_index > 0;
if (is_mangled and is_export) {
@@ -1769,7 +1881,7 @@ pub const DeclGen = struct {
fmtIdent(external_name),
fmtStringLiteral(external_name, null),
fmtStringLiteral(
- ip.stringToSlice(maybe_exports.?.items[0].opts.name),
+ maybe_exports.?.items[0].opts.name.toSlice(ip),
null,
),
});
@@ -1780,14 +1892,14 @@ pub const DeclGen = struct {
} else if (is_export) {
try w.print(" zig_export({s}, {s})", .{
fmtStringLiteral(
- ip.stringToSlice(maybe_exports.?.items[0].opts.name),
+ maybe_exports.?.items[0].opts.name.toSlice(ip),
null,
),
fmtStringLiteral(external_name, null),
});
}
},
- .ident => {},
+ .ident, .fmt_ctype_pool_string => {},
}
},
.complete => {},
@@ -1815,11 +1927,11 @@ pub const DeclGen = struct {
/// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
/// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
///
- fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
+ fn renderType(dg: *DeclGen, w: anytype, t: Type) error{OutOfMemory}!void {
try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
}
- fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void {
+ fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{OutOfMemory}!void {
_ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
}
@@ -1844,7 +1956,26 @@ pub const DeclGen = struct {
}
}
};
+ fn intCastIsNoop(dg: *DeclGen, dest_ty: Type, src_ty: Type) bool {
+ const zcu = dg.zcu;
+ const dest_bits = dest_ty.bitSize(zcu);
+ const dest_int_info = dest_ty.intInfo(zcu);
+
+ const src_is_ptr = src_ty.isPtrAtRuntime(zcu);
+ const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) {
+ .unsigned => Type.usize,
+ .signed => Type.isize,
+ } else src_ty;
+ const src_bits = src_eff_ty.bitSize(zcu);
+ const src_int_info = if (src_eff_ty.isAbiInt(zcu)) src_eff_ty.intInfo(zcu) else null;
+ if (dest_bits <= 64 and src_bits <= 64) {
+ const needs_cast = src_int_info == null or
+ (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or
+ dest_int_info.signedness != src_int_info.?.signedness);
+ return !needs_cast and !src_is_ptr;
+ } else return false;
+ }
/// Renders a cast to an int type, from either an int or a pointer.
///
/// Some platforms don't have 128 bit integers, so we need to use
@@ -1858,7 +1989,14 @@ pub const DeclGen = struct {
/// | > 64 bit integer | pointer | zig_make_<dest_ty>(0, (zig_<u|i>size)src)
/// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src)
/// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
- fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {
+ fn renderIntCast(
+ dg: *DeclGen,
+ w: anytype,
+ dest_ty: Type,
+ context: IntCastContext,
+ src_ty: Type,
+ location: ValueRenderLocation,
+ ) !void {
const zcu = dg.zcu;
const dest_bits = dest_ty.bitSize(zcu);
const dest_int_info = dest_ty.intInfo(zcu);
@@ -2013,12 +2151,23 @@ pub const DeclGen = struct {
fmtIdent("payload"),
fmtIdent(ident),
}),
+ .ctype_pool_string => |string| try w.print("{ }", .{
+ fmtCTypePoolString(string, &dg.ctype_pool),
+ }),
}
}
fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
switch (c_value) {
- .none, .new_local, .local, .local_ref, .constant, .arg, .arg_array => unreachable,
+ .none,
+ .new_local,
+ .local,
+ .local_ref,
+ .constant,
+ .arg,
+ .arg_array,
+ .ctype_pool_string,
+ => unreachable,
.field => |i| try w.print("f{d}", .{i}),
.decl => |decl| {
try w.writeAll("(*");
@@ -2048,7 +2197,17 @@ pub const DeclGen = struct {
fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
switch (c_value) {
- .none, .new_local, .local, .local_ref, .constant, .field, .undef, .arg, .arg_array => unreachable,
+ .none,
+ .new_local,
+ .local,
+ .local_ref,
+ .constant,
+ .field,
+ .undef,
+ .arg,
+ .arg_array,
+ .ctype_pool_string,
+ => unreachable,
.decl, .identifier, .payload_identifier => {
try dg.writeCValue(writer, c_value);
try writer.writeAll("->");
@@ -2088,12 +2247,12 @@ pub const DeclGen = struct {
.complete,
);
mangled: {
- const external_name = zcu.intern_pool.stringToSlice(if (maybe_exports) |exports|
+ const external_name = (if (maybe_exports) |exports|
exports.items[0].opts.name
else if (variable.is_extern)
decl.name
else
- break :mangled);
+ break :mangled).toSlice(&zcu.intern_pool);
if (isMangledIdent(external_name, true)) {
try fwd.print(" zig_mangled_{s}({ }, {s})", .{
@tagName(fwd_kind),
@@ -2107,15 +2266,16 @@ pub const DeclGen = struct {
fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void {
const zcu = dg.zcu;
+ const ip = &zcu.intern_pool;
const decl = zcu.declPtr(decl_index);
if (zcu.decl_exports.get(decl_index)) |exports| {
try writer.print("{ }", .{
- fmtIdent(zcu.intern_pool.stringToSlice(exports.items[export_index].opts.name)),
+ fmtIdent(exports.items[export_index].opts.name.toSlice(ip)),
});
} else if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| {
try writer.print("{ }", .{
- fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(extern_decl_index).name)),
+ fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
});
} else {
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
@@ -2186,11 +2346,7 @@ pub const DeclGen = struct {
loc: ValueRenderLocation,
) !std.fmt.Formatter(formatIntLiteral) {
const zcu = dg.zcu;
- const kind: CType.Kind = switch (loc) {
- .FunctionArgument => .parameter,
- .Initializer, .Other => .complete,
- .StaticInitializer => .global,
- };
+ const kind = loc.toCTypeKind();
const ty = val.typeOf(zcu);
return std.fmt.Formatter(formatIntLiteral){ .data = .{
.dg = dg,
@@ -2239,7 +2395,7 @@ fn renderFwdDeclTypeName(
switch (fwd_decl.name) {
.anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
.owner_decl => |owner_decl| try w.print("{}__{d}", .{
- fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
+ fmtIdent(zcu.declPtr(owner_decl).name.toSlice(&zcu.intern_pool)),
@intFromEnum(owner_decl),
}),
}
@@ -2453,7 +2609,7 @@ fn renderFields(
.suffix,
.{},
);
- try writer.print("{}{ }", .{ trailing, fmtIdent(field_info.name.slice(ctype_pool)) });
+ try writer.print("{}{ }", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool) });
try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});
try writer.writeAll(";\n");
}
@@ -2561,7 +2717,7 @@ pub fn genErrDecls(o: *Object) !void {
try writer.writeAll("enum {\n");
o.indent_writer.pushIndent();
for (zcu.global_error_set.keys()[1..], 1..) |name_nts, value| {
- const name = ip.stringToSlice(name_nts);
+ const name = name_nts.toSlice(ip);
max_name_len = @max(name.len, max_name_len);
const err_val = try zcu.intern(.{ .err = .{
.ty = .anyerror_type,
@@ -2579,19 +2735,19 @@ pub fn genErrDecls(o: *Object) !void {
defer o.dg.gpa.free(name_buf);
@memcpy(name_buf[0..name_prefix.len], name_prefix);
- for (zcu.global_error_set.keys()) |name_ip| {
- const name = ip.stringToSlice(name_ip);
- @memcpy(name_buf[name_prefix.len..][0..name.len], name);
- const identifier = name_buf[0 .. name_prefix.len + name.len];
+ for (zcu.global_error_set.keys()) |name| {
+ const name_slice = name.toSlice(ip);
+ @memcpy(name_buf[name_prefix.len..][0..name_slice.len], name_slice);
+ const identifier = name_buf[0 .. name_prefix.len + name_slice.len];
const name_ty = try zcu.arrayType(.{
- .len = name.len,
+ .len = name_slice.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const name_val = try zcu.intern(.{ .aggregate = .{
.ty = name_ty.toIntern(),
- .storage = .{ .bytes = name },
+ .storage = .{ .bytes = name.toString() },
} });
try writer.writeAll("static ");
@@ -2624,7 +2780,7 @@ pub fn genErrDecls(o: *Object) !void {
);
try writer.writeAll(" = {");
for (zcu.global_error_set.keys(), 0..) |name_nts, value| {
- const name = ip.stringToSlice(name_nts);
+ const name = name_nts.toSlice(ip);
if (value != 0) try writer.writeByte(',');
try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
fmtIdent(name),
@@ -2672,7 +2828,7 @@ fn genExports(o: *Object) !void {
for (exports.items[1..]) |@"export"| {
try fwd.writeAll("zig_extern ");
if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
- const export_name = ip.stringToSlice(@"export".opts.name);
+ const export_name = @"export".opts.name.toSlice(ip);
try o.dg.renderTypeAndName(
fwd,
decl.typeOf(zcu),
@@ -2685,11 +2841,11 @@ fn genExports(o: *Object) !void {
try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
fmtIdent(export_name),
fmtStringLiteral(export_name, null),
- fmtStringLiteral(ip.stringToSlice(exports.items[0].opts.name), null),
+ fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
});
} else {
try fwd.print(" zig_export({s}, {s})", .{
- fmtStringLiteral(ip.stringToSlice(exports.items[0].opts.name), null),
+ fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
fmtStringLiteral(export_name, null),
});
}
@@ -2712,24 +2868,23 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
try w.writeAll("static ");
try o.dg.renderType(w, name_slice_ty);
- try w.writeByte(' ');
- try w.writeAll(val.fn_name.slice(lazy_ctype_pool));
- try w.writeByte('(');
+ try w.print(" {}(", .{val.fn_name.fmt(lazy_ctype_pool)});
try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
try w.writeAll(") {\n switch (tag) {\n");
const tag_names = enum_ty.enumFields(zcu);
for (0..tag_names.len) |tag_index| {
- const tag_name = ip.stringToSlice(tag_names.get(ip)[tag_index]);
+ const tag_name = tag_names.get(ip)[tag_index];
+ const tag_name_len = tag_name.length(ip);
const tag_val = try zcu.enumValueFieldIndex(enum_ty, @intCast(tag_index));
const name_ty = try zcu.arrayType(.{
- .len = tag_name.len,
+ .len = tag_name_len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const name_val = try zcu.intern(.{ .aggregate = .{
.ty = name_ty.toIntern(),
- .storage = .{ .bytes = tag_name },
+ .storage = .{ .bytes = tag_name.toString() },
} });
try w.print(" case {}: {{\n static ", .{
@@ -2742,7 +2897,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
try o.dg.renderType(w, name_slice_ty);
try w.print("){{{}, {}}};\n", .{
fmtIdent("name"),
- try o.dg.fmtIntLiteral(try zcu.intValue(Type.usize, tag_name.len), .Other),
+ try o.dg.fmtIntLiteral(try zcu.intValue(Type.usize, tag_name_len), .Other),
});
try w.writeAll(" }\n");
@@ -2757,21 +2912,18 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
const fn_decl = zcu.declPtr(fn_decl_index);
const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
const fn_info = fn_ctype.info(ctype_pool).function;
- const fn_name = val.fn_name.slice(lazy_ctype_pool);
+ const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
const fwd_decl_writer = o.dg.fwdDeclWriter();
try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(
- fwd_decl_writer,
- fn_decl_index,
- .forward,
- .{ .ident = fn_name },
- );
+ try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{
+ .fmt_ctype_pool_string = fn_name,
+ });
try fwd_decl_writer.writeAll(";\n");
try w.print("static zig_{s} ", .{@tagName(key)});
try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
- .ident = fn_name,
+ .fmt_ctype_pool_string = fn_name,
});
try w.writeAll(" {\n return ");
try o.dg.renderDeclName(w, fn_decl_index, 0);
@@ -2810,7 +2962,7 @@ pub fn genFunc(f: *Function) !void {
try o.indent_writer.insertNewline();
if (!is_global) try o.writer().writeAll("static ");
- if (zcu.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
+ if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
try o.writer().writeByte(' ');
@@ -2900,7 +3052,7 @@ pub fn genDecl(o: *Object) !void {
if (!is_global) try w.writeAll("static ");
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
- if (zcu.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
+ if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
const decl_c_value = .{ .decl = decl_index };
try o.dg.renderTypeAndName(w, decl_ty, decl_c_value, .{}, decl.alignment, .complete);
@@ -2933,7 +3085,7 @@ pub fn genDeclValue(
switch (o.dg.pass) {
.decl => |decl_index| {
if (zcu.decl_exports.get(decl_index)) |exports| {
- const export_name = zcu.intern_pool.stringToSlice(exports.items[0].opts.name);
+ const export_name = exports.items[0].opts.name.toSlice(&zcu.intern_pool);
if (isMangledIdent(export_name, true)) {
try fwd_decl_writer.print(" zig_mangled_final({ }, {s})", .{
fmtIdent(export_name), fmtStringLiteral(export_name, null),
@@ -2949,7 +3101,7 @@ pub fn genDeclValue(
const w = o.writer();
if (!is_global) try w.writeAll("static ");
- if (zcu.intern_pool.stringToSliceUnwrap(@"linksection")) |s|
+ if (@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
try w.writeAll(" = ");
@@ -3156,8 +3308,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.shl_exact => try airBinOp(f, inst, "<<", "shl", .none),
.not => try airNot (f, inst),
- .optional_payload => try airOptionalPayload(f, inst),
- .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),
+ .optional_payload => try airOptionalPayload(f, inst, false),
+ .optional_payload_ptr => try airOptionalPayload(f, inst, true),
.optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),
.wrap_optional => try airWrapOptional(f, inst),
@@ -3166,10 +3318,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.is_err_ptr => try airIsErr(f, inst, true, "!="),
.is_non_err_ptr => try airIsErr(f, inst, true, "=="),
- .is_null => try airIsNull(f, inst, "==", false),
- .is_non_null => try airIsNull(f, inst, "!=", false),
- .is_null_ptr => try airIsNull(f, inst, "==", true),
- .is_non_null_ptr => try airIsNull(f, inst, "!=", true),
+ .is_null => try airIsNull(f, inst, .eq, false),
+ .is_non_null => try airIsNull(f, inst, .neq, false),
+ .is_null_ptr => try airIsNull(f, inst, .eq, true),
+ .is_non_null_ptr => try airIsNull(f, inst, .neq, true),
.alloc => try airAlloc(f, inst),
.ret_ptr => try airRetPtr(f, inst),
@@ -3252,8 +3404,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.slice_ptr => try airSliceField(f, inst, false, "ptr"),
.slice_len => try airSliceField(f, inst, false, "len"),
- .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"),
.ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"),
+ .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"),
.ptr_elem_val => try airPtrElemVal(f, inst),
.ptr_elem_ptr => try airPtrElemPtr(f, inst),
@@ -3321,7 +3473,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
}
try f.value_map.putNoClobber(inst.toRef(), switch (result_value) {
.none => continue,
- .new_local => |i| .{ .local = i },
+ .new_local => |local_index| .{ .local = local_index },
else => result_value,
});
}
@@ -3336,7 +3488,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
if (is_ptr) {
@@ -3362,7 +3514,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, ptr, .Other);
@@ -3388,7 +3540,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try writer.writeByte('(');
@@ -3423,7 +3575,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" });
@@ -3450,7 +3602,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
if (elem_has_bits) try writer.writeByte('&');
@@ -3479,7 +3631,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, array, .Other);
@@ -3704,17 +3856,18 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
const operand_ty = f.typeOf(ty_op.operand);
const scalar_ty = operand_ty.scalarType(zcu);
+ if (f.object.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand);
+
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, writer, operand_ty);
- const a = try Assignment.start(f, writer, scalar_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
try f.writeCValue(writer, local, .Other);
try v.elem(f, writer);
try a.assign(f, writer);
try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other);
try a.end(f, writer);
try v.end(f, inst, writer);
-
return local;
}
@@ -3724,38 +3877,40 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
+
const inst_ty = f.typeOfIndex(inst);
const inst_scalar_ty = inst_ty.scalarType(zcu);
const dest_int_info = inst_scalar_ty.intInfo(zcu);
const dest_bits = dest_int_info.bits;
- const dest_c_bits = toCIntBits(dest_int_info.bits) orelse
+ const dest_c_bits = toCIntBits(dest_bits) orelse
return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
const operand_ty = f.typeOf(ty_op.operand);
const scalar_ty = operand_ty.scalarType(zcu);
const scalar_int_info = scalar_ty.intInfo(zcu);
+ const need_cast = dest_c_bits < 64;
+ const need_lo = scalar_int_info.bits > 64 and dest_bits <= 64;
+ const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits);
+ if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand);
+
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, writer, operand_ty);
-
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
try f.writeCValue(writer, local, .Other);
try v.elem(f, writer);
- try writer.writeAll(" = ");
-
- if (dest_c_bits < 64) {
+ try a.assign(f, writer);
+ if (need_cast) {
try writer.writeByte('(');
try f.renderType(writer, inst_scalar_ty);
try writer.writeByte(')');
}
-
- const needs_lo = scalar_int_info.bits > 64 and dest_bits <= 64;
- if (needs_lo) {
+ if (need_lo) {
try writer.writeAll("zig_lo_");
try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
try writer.writeByte('(');
}
-
- if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
+ if (!need_mask) {
try f.writeCValue(writer, operand, .Other);
try v.elem(f, writer);
} else switch (dest_int_info.signedness) {
@@ -3795,11 +3950,9 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)});
},
}
-
- if (needs_lo) try writer.writeByte(')');
- try writer.writeAll(";\n");
+ if (need_lo) try writer.writeByte(')');
+ try a.end(f, writer);
try v.end(f, inst, writer);
-
return local;
}
@@ -3810,7 +3963,7 @@ fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const inst_ty = f.typeOfIndex(inst);
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, operand, .Other);
@@ -3855,9 +4008,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const src_val = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ const src_scalar_ctype = try f.ctypeFromType(src_ty.scalarType(zcu), .complete);
const writer = f.object.writer();
- const v = try Vectorize.start(f, inst, writer, ptr_ty);
-
if (need_memcpy) {
// For this memcpy to safely work we need the rhs to have the same
// underlying type as the lhs (i.e. they must both be arrays of the same underlying type).
@@ -3876,6 +4028,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
break :blk new_local;
} else src_val;
+ const v = try Vectorize.start(f, inst, writer, ptr_ty);
try writer.writeAll("memcpy((char *)");
try f.writeCValue(writer, ptr_val, .FunctionArgument);
try v.elem(f, writer);
@@ -3886,9 +4039,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
try writer.writeAll(", sizeof(");
try f.renderType(writer, src_ty);
try writer.writeAll("))");
- if (src_val == .constant) {
- try freeLocal(f, inst, array_src.new_local, null);
- }
+ try f.freeCValue(inst, array_src);
+ try writer.writeAll(";\n");
+ try v.end(f, inst, writer);
} else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) {
const host_bits = ptr_info.packed_offset.host_size * 8;
const host_ty = try zcu.intType(.unsigned, host_bits);
@@ -3911,9 +4064,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const mask_val = try zcu.intValue_big(host_ty, mask.toConst());
+ const v = try Vectorize.start(f, inst, writer, ptr_ty);
+ const a = try Assignment.start(f, writer, src_scalar_ctype);
try f.writeCValueDeref(writer, ptr_val);
try v.elem(f, writer);
- try writer.writeAll(" = zig_or_");
+ try a.assign(f, writer);
+ try writer.writeAll("zig_or_");
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
try writer.writeAll("(zig_and_");
try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
@@ -3944,16 +4100,27 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
try v.elem(f, writer);
if (cant_cast) try writer.writeByte(')');
try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)});
+ try a.end(f, writer);
+ try v.end(f, inst, writer);
} else {
+ switch (ptr_val) {
+ .local_ref => |ptr_local_index| switch (src_val) {
+ .new_local, .local => |src_local_index| if (ptr_local_index == src_local_index)
+ return .none,
+ else => {},
+ },
+ else => {},
+ }
+ const v = try Vectorize.start(f, inst, writer, ptr_ty);
+ const a = try Assignment.start(f, writer, src_scalar_ctype);
try f.writeCValueDeref(writer, ptr_val);
try v.elem(f, writer);
- try writer.writeAll(" = ");
+ try a.assign(f, writer);
try f.writeCValue(writer, src_val, .Other);
try v.elem(f, writer);
+ try a.end(f, writer);
+ try v.end(f, inst, writer);
}
- try writer.writeAll(";\n");
- try v.end(f, inst, writer);
-
return .none;
}
@@ -4116,6 +4283,7 @@ fn airEquality(
operator: std.math.CompareOperator,
) !CValue {
const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const operand_ty = f.typeOf(bin_op.lhs);
@@ -4137,28 +4305,47 @@ fn airEquality(
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const writer = f.object.writer();
- const inst_ty = f.typeOfIndex(inst);
- const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const local = try f.allocLocal(inst, Type.bool);
+ const a = try Assignment.start(f, writer, CType.bool);
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
- if (operand_ty.zigTypeTag(zcu) == .Optional and !operand_ty.optionalReprIsPayload(zcu)) {
- try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
- try writer.writeAll(" || ");
- try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
- try writer.writeAll(" ? ");
- try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
- try writer.writeAll(compareOperatorC(operator));
- try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
- try writer.writeAll(" : ");
- try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" });
- try writer.writeAll(compareOperatorC(operator));
- try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" });
- } else {
- try f.writeCValue(writer, lhs, .Other);
- try writer.writeAll(compareOperatorC(operator));
- try f.writeCValue(writer, rhs, .Other);
+ const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
+ switch (operand_ctype.info(ctype_pool)) {
+ .basic, .pointer => {
+ try f.writeCValue(writer, lhs, .Other);
+ try writer.writeAll(compareOperatorC(operator));
+ try f.writeCValue(writer, rhs, .Other);
+ },
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| if (aggregate.fields.len == 2 and
+ (aggregate.fields.at(0, ctype_pool).name.index == .is_null or
+ aggregate.fields.at(1, ctype_pool).name.index == .is_null))
+ {
+ try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
+ try writer.writeAll(" || ");
+ try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
+ try writer.writeAll(" ? ");
+ try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
+ try writer.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
+ try writer.writeAll(" : ");
+ try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" });
+ try writer.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" });
+ } else for (0..aggregate.fields.len) |field_index| {
+ if (field_index > 0) try writer.writeAll(switch (operator) {
+ .lt, .lte, .gte, .gt => unreachable,
+ .eq => " && ",
+ .neq => " || ",
+ });
+ const field_name: CValue = .{
+ .ctype_pool_string = aggregate.fields.at(field_index, ctype_pool).name,
+ };
+ try f.writeCValueMember(writer, lhs, field_name);
+ try writer.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(writer, rhs, field_name);
+ },
}
try a.end(f, writer);
@@ -4168,12 +4355,11 @@ fn airEquality(
fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
- const inst_ty = f.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const writer = f.object.writer();
- const local = try f.allocLocal(inst, inst_ty);
+ const local = try f.allocLocal(inst, Type.bool);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = ");
try f.writeCValue(writer, operand, .Other);
@@ -4193,39 +4379,34 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
const inst_ty = f.typeOfIndex(inst);
const inst_scalar_ty = inst_ty.scalarType(zcu);
const elem_ty = inst_scalar_ty.elemType2(zcu);
+ if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);
+ const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
const local = try f.allocLocal(inst, inst_ty);
const writer = f.object.writer();
const v = try Vectorize.start(f, inst, writer, inst_ty);
+ const a = try Assignment.start(f, writer, inst_scalar_ctype);
try f.writeCValue(writer, local, .Other);
try v.elem(f, writer);
- try writer.writeAll(" = ");
-
- if (elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- // We must convert to and from integer types to prevent UB if the operation
- // results in a NULL pointer, or if LHS is NULL. The operation is only UB
- // if the result is NULL and then dereferenced.
- try writer.writeByte('(');
- try f.renderType(writer, inst_scalar_ty);
- try writer.writeAll(")(((uintptr_t)");
- try f.writeCValue(writer, lhs, .Other);
- try v.elem(f, writer);
- try writer.writeAll(") ");
- try writer.writeByte(operator);
- try writer.writeAll(" (");
- try f.writeCValue(writer, rhs, .Other);
- try v.elem(f, writer);
- try writer.writeAll("*sizeof(");
- try f.renderType(writer, elem_ty);
- try writer.writeAll(")))");
- } else {
- try f.writeCValue(writer, lhs, .Other);
- try v.elem(f, writer);
- }
-
- try writer.writeAll(";\n");
+ try a.assign(f, writer);
+ // We must convert to and from integer types to prevent UB if the operation
+ // results in a NULL pointer, or if LHS is NULL. The operation is only UB
+ // if the result is NULL and then dereferenced.
+ try writer.writeByte('(');
+ try f.renderCType(writer, inst_scalar_ctype);
+ try writer.writeAll(")(((uintptr_t)");
+ try f.writeCValue(writer, lhs, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll(") ");
+ try writer.writeByte(operator);
+ try writer.writeAll(" (");
+ try f.writeCValue(writer, rhs, .Other);
+ try v.elem(f, writer);
+ try writer.writeAll("*sizeof(");
+ try f.renderType(writer, elem_ty);
+ try writer.writeAll(")))");
+ try a.end(f, writer);
try v.end(f, inst, writer);
-
return local;
}
@@ -4286,14 +4467,14 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
{
- const a = try Assignment.start(f, writer, ptr_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
try a.assign(f, writer);
try f.writeCValue(writer, ptr, .Other);
try a.end(f, writer);
}
{
- const a = try Assignment.start(f, writer, Type.usize);
+ const a = try Assignment.start(f, writer, CType.usize);
try f.writeCValueMember(writer, local, .{ .identifier = "len" });
try a.assign(f, writer);
try f.writeCValue(writer, len, .Initializer);
@@ -4360,7 +4541,7 @@ fn airCall(
}).?;
const ret_ty = Type.fromInterned(fn_info.return_type);
const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))
- .{ .index = .void }
+ CType.void
else
try f.ctypeFromType(ret_ty, .parameter);
@@ -4372,7 +4553,7 @@ fn airCall(
break :result .none;
} else if (f.liveness.isUnused(inst)) {
try writer.writeByte('(');
- try f.renderCType(writer, .{ .index = .void });
+ try f.renderCType(writer, CType.void);
try writer.writeByte(')');
break :result .none;
} else {
@@ -4427,10 +4608,7 @@ fn airCall(
if (need_comma) try writer.writeAll(", ");
need_comma = true;
try f.writeCValue(writer, resolved_arg, .FunctionArgument);
- switch (resolved_arg) {
- .new_local => |local| try freeLocal(f, inst, local, null),
- else => {},
- }
+ try f.freeCValue(inst, resolved_arg);
}
try writer.writeAll(");\n");
@@ -4614,7 +4792,7 @@ fn lowerTry(
}
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
if (is_ptr) {
@@ -4637,7 +4815,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(branch.operand);
try reap(f, inst, &.{branch.operand});
- const a = try Assignment.start(f, writer, operand_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
try f.writeCValue(writer, result, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, operand, .Other);
@@ -4650,53 +4828,17 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
- const dest_ty = f.typeOfIndex(inst);
+ const inst_ty = f.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
const operand_ty = f.typeOf(ty_op.operand);
- const bitcasted = try bitcast(f, dest_ty, operand, operand_ty);
+ const bitcasted = try bitcast(f, inst_ty, operand, operand_ty);
try reap(f, inst, &.{ty_op.operand});
- return bitcasted.move(f, inst, dest_ty);
+ return f.moveCValue(inst, inst_ty, bitcasted);
}
-const LocalResult = struct {
- c_value: CValue,
- need_free: bool,
-
- fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue {
- const zcu = f.object.dg.zcu;
-
- if (lr.need_free) {
- // Move the freshly allocated local to be owned by this instruction,
- // by returning it here instead of freeing it.
- return lr.c_value;
- }
-
- const local = try f.allocLocal(inst, dest_ty);
- try lr.free(f);
- const writer = f.object.writer();
- try f.writeCValue(writer, local, .Other);
- if (dest_ty.isAbiInt(zcu)) {
- try writer.writeAll(" = ");
- } else {
- try writer.writeAll(" = (");
- try f.renderType(writer, dest_ty);
- try writer.writeByte(')');
- }
- try f.writeCValue(writer, lr.c_value, .Initializer);
- try writer.writeAll(";\n");
- return local;
- }
-
- fn free(lr: LocalResult, f: *Function) !void {
- if (lr.need_free) {
- try freeLocal(f, null, lr.c_value.new_local, null);
- }
- }
-};
-
-fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
+fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CValue {
const zcu = f.object.dg.zcu;
const target = &f.object.dg.mod.resolved_target.result;
const ctype_pool = &f.object.dg.ctype_pool;
@@ -4706,13 +4848,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
const src_info = dest_ty.intInfo(zcu);
const dest_info = operand_ty.intInfo(zcu);
if (src_info.signedness == dest_info.signedness and
- src_info.bits == dest_info.bits)
- {
- return .{
- .c_value = operand,
- .need_free = false,
- };
- }
+ src_info.bits == dest_info.bits) return operand;
}
if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) {
@@ -4723,10 +4859,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
try writer.writeByte(')');
try f.writeCValue(writer, operand, .Other);
try writer.writeAll(";\n");
- return .{
- .c_value = local,
- .need_free = true,
- };
+ return local;
}
const operand_lval = if (operand == .constant) blk: {
@@ -4813,14 +4946,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
try writer.writeAll(");\n");
}
- if (operand == .constant) {
- try freeLocal(f, null, operand_lval.new_local, null);
- }
-
- return .{
- .c_value = local,
- .need_free = true,
- };
+ try f.freeCValue(null, operand_lval);
+ return local;
}
fn airTrap(f: *Function, writer: anytype) !CValue {
@@ -4931,13 +5058,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
try writer.writeAll("switch (");
- if (condition_ty.zigTypeTag(zcu) == .Bool) {
- try writer.writeByte('(');
- try f.renderType(writer, Type.u1);
- try writer.writeByte(')');
- } else if (condition_ty.isPtrAtRuntime(zcu)) {
+
+ const lowered_condition_ty = if (condition_ty.toIntern() == .bool_type)
+ Type.u1
+ else if (condition_ty.isPtrAtRuntime(zcu))
+ Type.usize
+ else
+ condition_ty;
+ if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) {
try writer.writeByte('(');
- try f.renderType(writer, Type.usize);
+ try f.renderType(writer, lowered_condition_ty);
try writer.writeByte(')');
}
try f.writeCValue(writer, condition, .Other);
@@ -4956,18 +5086,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
for (0..switch_br.data.cases_len) |case_i| {
const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
const items = @as([]const Air.Inst.Ref, @ptrCast(f.air.extra[case.end..][0..case.data.items_len]));
- const case_body: []const Air.Inst.Index = @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]);
+ const case_body: []const Air.Inst.Index =
+ @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]);
extra_index = case.end + case.data.items_len + case_body.len;
for (items) |item| {
try f.object.indent_writer.insertNewline();
try writer.writeAll("case ");
- if (condition_ty.isPtrAtRuntime(zcu)) {
- try writer.writeByte('(');
- try f.renderType(writer, Type.usize);
- try writer.writeByte(')');
+ const item_value = try f.air.value(item, zcu);
+ if (item_value.?.getUnsignedInt(zcu)) |item_int| try writer.print("{}\n", .{
+ try f.fmtIntLiteral(try zcu.intValue(lowered_condition_ty, item_int)),
+ }) else {
+ if (condition_ty.isPtrAtRuntime(zcu)) {
+ try writer.writeByte('(');
+ try f.renderType(writer, Type.usize);
+ try writer.writeByte(')');
+ }
+ try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other);
}
- try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other);
try writer.writeByte(':');
}
try writer.writeByte(' ');
@@ -5289,10 +5425,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
fn airIsNull(
f: *Function,
inst: Air.Inst.Index,
- operator: []const u8,
+ operator: std.math.CompareOperator,
is_ptr: bool,
) !CValue {
const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const writer = f.object.writer();
@@ -5300,106 +5437,84 @@ fn airIsNull(
try reap(f, inst, &.{un_op});
const local = try f.allocLocal(inst, Type.bool);
+ const a = try Assignment.start(f, writer, CType.bool);
try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
- if (is_ptr) {
- try f.writeCValueDeref(writer, operand);
- } else {
- try f.writeCValue(writer, operand, .Other);
- }
+ try a.assign(f, writer);
const operand_ty = f.typeOf(un_op);
const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
- const payload_ty = optional_ty.optionalChild(zcu);
- const err_int_ty = try zcu.errorIntType();
-
- const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
- Value.true
- else if (optional_ty.isPtrLikeOptional(zcu))
- // operand is a regular pointer, test `operand !=/== NULL`
- try zcu.getCoerced(Value.null, optional_ty)
- else if (payload_ty.zigTypeTag(zcu) == .ErrorSet)
- try zcu.intValue(err_int_ty, 0)
- else if (payload_ty.isSlice(zcu) and optional_ty.optionalReprIsPayload(zcu)) rhs: {
- try writer.writeAll(".ptr");
- const slice_ptr_ty = payload_ty.slicePtrFieldType(zcu);
- const opt_slice_ptr_ty = try zcu.optionalType(slice_ptr_ty.toIntern());
- break :rhs try zcu.nullValue(opt_slice_ptr_ty);
- } else rhs: {
- try writer.writeAll(".is_null");
- break :rhs Value.true;
+ const opt_ctype = try f.ctypeFromType(optional_ty, .complete);
+ const rhs = switch (opt_ctype.info(ctype_pool)) {
+ .basic, .pointer => rhs: {
+ if (is_ptr)
+ try f.writeCValueDeref(writer, operand)
+ else
+ try f.writeCValue(writer, operand, .Other);
+ break :rhs if (opt_ctype.isBool())
+ "true"
+ else if (opt_ctype.isInteger())
+ "0"
+ else
+ "NULL";
+ },
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
+ .is_null, .payload => rhs: {
+ if (is_ptr)
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" })
+ else
+ try f.writeCValueMember(writer, operand, .{ .identifier = "is_null" });
+ break :rhs "true";
+ },
+ .ptr, .len => rhs: {
+ if (is_ptr)
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "ptr" })
+ else
+ try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" });
+ break :rhs "NULL";
+ },
+ else => unreachable,
+ },
};
- try writer.writeByte(' ');
- try writer.writeAll(operator);
- try writer.writeByte(' ');
- try f.object.dg.renderValue(writer, rhs, .Other);
- try writer.writeAll(";\n");
- return local;
-}
-
-fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
- const zcu = f.object.dg.zcu;
- const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
-
- const operand = try f.resolveInst(ty_op.operand);
- try reap(f, inst, &.{ty_op.operand});
- const opt_ty = f.typeOf(ty_op.operand);
-
- const payload_ty = opt_ty.optionalChild(zcu);
-
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return .none;
- }
-
- const inst_ty = f.typeOfIndex(inst);
- const writer = f.object.writer();
- const local = try f.allocLocal(inst, inst_ty);
-
- if (opt_ty.optionalReprIsPayload(zcu)) {
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
- try f.writeCValue(writer, operand, .Other);
- try writer.writeAll(";\n");
- return local;
- }
-
- const a = try Assignment.start(f, writer, inst_ty);
- try f.writeCValue(writer, local, .Other);
- try a.assign(f, writer);
- try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
+ try writer.writeAll(compareOperatorC(operator));
+ try writer.writeAll(rhs);
try a.end(f, writer);
return local;
}
-fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
+fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
- const writer = f.object.writer();
- const operand = try f.resolveInst(ty_op.operand);
- try reap(f, inst, &.{ty_op.operand});
- const ptr_ty = f.typeOf(ty_op.operand);
- const opt_ty = ptr_ty.childType(zcu);
const inst_ty = f.typeOfIndex(inst);
+ const operand_ty = f.typeOf(ty_op.operand);
+ const opt_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
+ const opt_ctype = try f.ctypeFromType(opt_ty, .complete);
+ if (opt_ctype.isBool()) return if (is_ptr) .{ .undef = inst_ty } else .none;
- if (!inst_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) {
- return .{ .undef = inst_ty };
- }
-
- const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(writer, local, .Other);
-
- if (opt_ty.optionalReprIsPayload(zcu)) {
- // the operand is just a regular pointer, no need to do anything special.
- // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C
- try writer.writeAll(" = ");
- try f.writeCValue(writer, operand, .Other);
- } else {
- try writer.writeAll(" = &");
- try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
+ const operand = try f.resolveInst(ty_op.operand);
+ switch (opt_ctype.info(ctype_pool)) {
+ .basic, .pointer => return f.moveCValue(inst, inst_ty, operand),
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
+ .is_null, .payload => {
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
+ try f.writeCValue(writer, local, .Other);
+ try a.assign(f, writer);
+ if (is_ptr) {
+ try writer.writeByte('&');
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
+ } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
+ try a.end(f, writer);
+ return local;
+ },
+ .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
+ else => unreachable,
+ },
}
- try writer.writeAll(";\n");
- return local;
}
fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -5410,38 +5525,46 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ty_op.operand});
const operand_ty = f.typeOf(ty_op.operand);
- const opt_ty = operand_ty.childType(zcu);
-
const inst_ty = f.typeOfIndex(inst);
-
- if (opt_ty.optionalReprIsPayload(zcu)) {
- if (f.liveness.isUnused(inst)) {
- return .none;
- }
- const local = try f.allocLocal(inst, inst_ty);
- // The payload and the optional are the same value.
- // Setting to non-null will be done when the payload is set.
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
- try f.writeCValue(writer, operand, .Other);
- try writer.writeAll(";\n");
- return local;
- } else {
- try f.writeCValueDeref(writer, operand);
- try writer.writeAll(".is_null = ");
- try f.object.dg.renderValue(writer, Value.false, .Initializer);
- try writer.writeAll(";\n");
-
- if (f.liveness.isUnused(inst)) {
+ const opt_ctype = try f.ctypeFromType(operand_ty.childType(zcu), .complete);
+ switch (opt_ctype.info(&f.object.dg.ctype_pool)) {
+ .basic => {
+ const a = try Assignment.start(f, writer, opt_ctype);
+ try f.writeCValueDeref(writer, operand);
+ try a.assign(f, writer);
+ try f.object.dg.renderValue(writer, Value.false, .Initializer);
+ try a.end(f, writer);
return .none;
- }
-
- const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = &");
- try f.writeCValueDeref(writer, operand);
- try writer.writeAll(".payload;\n");
- return local;
+ },
+ .pointer => {
+ if (f.liveness.isUnused(inst)) return .none;
+ const local = try f.allocLocal(inst, inst_ty);
+ const a = try Assignment.start(f, writer, opt_ctype);
+ try f.writeCValue(writer, local, .Other);
+ try a.assign(f, writer);
+ try f.writeCValue(writer, operand, .Other);
+ try a.end(f, writer);
+ return local;
+ },
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => {
+ {
+ const a = try Assignment.start(f, writer, opt_ctype);
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
+ try a.assign(f, writer);
+ try f.object.dg.renderValue(writer, Value.false, .Initializer);
+ try a.end(f, writer);
+ }
+ if (f.liveness.isUnused(inst)) return .none;
+ const local = try f.allocLocal(inst, inst_ty);
+ const a = try Assignment.start(f, writer, opt_ctype);
+ try f.writeCValue(writer, local, .Other);
+ try a.assign(f, writer);
+ try writer.writeByte('&');
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
+ try a.end(f, writer);
+ return local;
+ },
}
}
@@ -5453,49 +5576,39 @@ fn fieldLocation(
) union(enum) {
begin: void,
field: CValue,
- byte_offset: u32,
- end: void,
+ byte_offset: u64,
} {
const ip = &zcu.intern_pool;
const container_ty = Type.fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
switch (ip.indexToKey(container_ty.toIntern())) {
.struct_type => {
const loaded_struct = ip.loadStructType(container_ty.toIntern());
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- var field_it = loaded_struct.iterateRuntimeOrder(ip);
- var before = true;
- while (field_it.next()) |next_field_index| {
- if (next_field_index == field_index) before = false;
- if (before) continue;
- const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[next_field_index]);
- if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- return .{ .field = if (loaded_struct.fieldName(ip, next_field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
- else
- .{ .field = next_field_index } };
- }
- return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
- },
- .@"packed" => return if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
+ return switch (loaded_struct.layout) {
+ .auto, .@"extern" => if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ .begin
+ else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu))
+ .{ .byte_offset = loaded_struct.offsets.get(ip)[field_index] }
+ else
+ .{ .field = if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
+ .{ .identifier = field_name.toSlice(ip) }
+ else
+ .{ .field = field_index } },
+ .@"packed" => if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
.{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) +
container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
else
.begin,
- }
- },
- .anon_struct_type => |anon_struct_info| {
- for (field_index..anon_struct_info.types.len) |next_field_index| {
- if (anon_struct_info.values.get(ip)[next_field_index] != .none) continue;
- const field_type = Type.fromInterned(anon_struct_info.types.get(ip)[next_field_index]);
- if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- return .{ .field = if (anon_struct_info.fieldName(ip, next_field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
- else
- .{ .field = next_field_index } };
- }
- return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
+ };
},
+ .anon_struct_type => |anon_struct_info| return if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ .begin
+ else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu))
+ .{ .byte_offset = container_ty.structFieldOffset(field_index, zcu) }
+ else
+ .{ .field = if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|
+ .{ .identifier = field_name.toSlice(ip) }
+ else
+ .{ .field = field_index } },
.union_type => {
const loaded_union = ip.loadUnionType(container_ty.toIntern());
switch (loaded_union.getLayout(ip)) {
@@ -5508,9 +5621,9 @@ fn fieldLocation(
.begin;
const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
return .{ .field = if (loaded_union.hasTag(ip))
- .{ .payload_identifier = ip.stringToSlice(field_name) }
+ .{ .payload_identifier = field_name.toSlice(ip) }
else
- .{ .identifier = ip.stringToSlice(field_name) } };
+ .{ .identifier = field_name.toSlice(ip) } };
},
.@"packed" => return .begin,
}
@@ -5591,10 +5704,6 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
try f.fmtIntLiteral(try zcu.intValue(Type.usize, byte_offset)),
});
},
- .end => {
- try f.writeCValue(writer, field_ptr_val, .Other);
- try writer.print(" - {}", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 1))});
- },
}
try writer.writeAll(";\n");
@@ -5639,11 +5748,6 @@ fn fieldPtr(
try f.fmtIntLiteral(try zcu.intValue(Type.usize, byte_offset)),
});
},
- .end => {
- try writer.writeByte('(');
- try f.writeCValue(writer, container_ptr_val, .Other);
- try writer.print(" + {})", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 1))});
- },
}
try writer.writeAll(";\n");
@@ -5675,7 +5779,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
const loaded_struct = ip.loadStructType(struct_ty.toIntern());
switch (loaded_struct.layout) {
.auto, .@"extern" => break :field_name if (loaded_struct.fieldName(ip, extra.field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
+ .{ .identifier = field_name.toSlice(ip) }
else
.{ .field = extra.field_index },
.@"packed" => {
@@ -5720,20 +5824,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
const local = try f.allocLocal(inst, inst_ty);
- try writer.writeAll("memcpy(");
- try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
- try writer.writeAll(", ");
- try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
- try writer.writeAll(", sizeof(");
- try f.renderType(writer, inst_ty);
- try writer.writeAll("));\n");
+ if (local.new_local != temp_local.new_local) {
+ try writer.writeAll("memcpy(");
+ try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
+ try writer.writeAll(", sizeof(");
+ try f.renderType(writer, inst_ty);
+ try writer.writeAll("));\n");
+ }
try freeLocal(f, inst, temp_local.new_local, null);
return local;
},
}
},
.anon_struct_type => |anon_struct_info| if (anon_struct_info.fieldName(ip, extra.field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
+ .{ .identifier = field_name.toSlice(ip) }
else
.{ .field = extra.field_index },
.union_type => field_name: {
@@ -5742,9 +5848,9 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
.auto, .@"extern" => {
const name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
break :field_name if (loaded_union.hasTag(ip))
- .{ .payload_identifier = ip.stringToSlice(name) }
+ .{ .payload_identifier = name.toSlice(ip) }
else
- .{ .identifier = ip.stringToSlice(name) };
+ .{ .identifier = name.toSlice(ip) };
},
.@"packed" => {
const operand_lval = if (struct_byval == .constant) blk: {
@@ -5755,20 +5861,23 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(";\n");
break :blk operand_local;
} else struct_byval;
-
const local = try f.allocLocal(inst, inst_ty);
- try writer.writeAll("memcpy(&");
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(", &");
- try f.writeCValue(writer, operand_lval, .Other);
- try writer.writeAll(", sizeof(");
- try f.renderType(writer, inst_ty);
- try writer.writeAll("));\n");
-
- if (struct_byval == .constant) {
- try freeLocal(f, inst, operand_lval.new_local, null);
+ if (switch (local) {
+ .new_local, .local => |local_index| switch (operand_lval) {
+ .new_local, .local => |operand_local_index| local_index != operand_local_index,
+ else => true,
+ },
+ else => true,
+ }) {
+ try writer.writeAll("memcpy(&");
+ try f.writeCValue(writer, local, .Other);
+ try writer.writeAll(", &");
+ try f.writeCValue(writer, operand_lval, .Other);
+ try writer.writeAll(", sizeof(");
+ try f.renderType(writer, inst_ty);
+ try writer.writeAll("));\n");
}
-
+ try f.freeCValue(inst, operand_lval);
return local;
},
}
@@ -5777,7 +5886,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
};
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValueMember(writer, struct_byval, field_name);
@@ -5850,7 +5959,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
}
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
if (is_ptr) {
@@ -5862,35 +5971,42 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
}
fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
- const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const inst_ty = f.typeOfIndex(inst);
- const repr_is_payload = inst_ty.optionalReprIsPayload(zcu);
- const payload_ty = f.typeOf(ty_op.operand);
- const payload = try f.resolveInst(ty_op.operand);
- try reap(f, inst, &.{ty_op.operand});
+ const inst_ctype = try f.ctypeFromType(inst_ty, .complete);
+ if (inst_ctype.isBool()) return .{ .constant = Value.true };
- const writer = f.object.writer();
- const local = try f.allocLocal(inst, inst_ty);
- {
- const a = try Assignment.start(f, writer, payload_ty);
- if (repr_is_payload)
- try f.writeCValue(writer, local, .Other)
- else
- try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
- try a.assign(f, writer);
- try f.writeCValue(writer, payload, .Other);
- try a.end(f, writer);
- }
- if (!repr_is_payload) {
- const a = try Assignment.start(f, writer, Type.bool);
- try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
- try a.assign(f, writer);
- try f.object.dg.renderValue(writer, Value.false, .Other);
- try a.end(f, writer);
+ const operand = try f.resolveInst(ty_op.operand);
+ switch (inst_ctype.info(ctype_pool)) {
+ .basic, .pointer => return f.moveCValue(inst, inst_ty, operand),
+ .aligned, .array, .vector, .fwd_decl, .function => unreachable,
+ .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
+ .is_null, .payload => {
+ const operand_ctype = try f.ctypeFromType(f.typeOf(ty_op.operand), .complete);
+ const writer = f.object.writer();
+ const local = try f.allocLocal(inst, inst_ty);
+ {
+ const a = try Assignment.start(f, writer, CType.bool);
+ try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
+ try a.assign(f, writer);
+ try writer.writeAll("false");
+ try a.end(f, writer);
+ }
+ {
+ const a = try Assignment.start(f, writer, operand_ctype);
+ try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
+ try a.assign(f, writer);
+ try f.writeCValue(writer, operand, .Initializer);
+ try a.end(f, writer);
+ }
+ return local;
+ },
+ .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
+ else => unreachable,
+ },
}
- return local;
}
fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -5913,14 +6029,14 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
}
if (!repr_is_err) {
- const a = try Assignment.start(f, writer, payload_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
try a.assign(f, writer);
try f.object.dg.renderUndefValue(writer, payload_ty, .Other);
try a.end(f, writer);
}
{
- const a = try Assignment.start(f, writer, err_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
if (repr_is_err)
try f.writeCValue(writer, local, .Other)
else
@@ -5936,31 +6052,43 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
const zcu = f.object.dg.zcu;
const writer = f.object.writer();
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
+ const inst_ty = f.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
- const error_union_ty = f.typeOf(ty_op.operand).childType(zcu);
+ const operand_ty = f.typeOf(ty_op.operand);
+ const error_union_ty = operand_ty.childType(zcu);
const payload_ty = error_union_ty.errorUnionPayload(zcu);
const err_int_ty = try zcu.errorIntType();
const no_err = try zcu.intValue(err_int_ty, 0);
+ try reap(f, inst, &.{ty_op.operand});
// First, set the non-error value.
if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
try f.writeCValueDeref(writer, operand);
- try writer.print(" = {};\n", .{try f.fmtIntLiteral(no_err)});
- return operand;
+ try a.assign(f, writer);
+ try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
+ try a.end(f, writer);
+ return .none;
+ }
+ {
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(err_int_ty, .complete));
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" });
+ try a.assign(f, writer);
+ try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
+ try a.end(f, writer);
}
- try reap(f, inst, &.{ty_op.operand});
- try f.writeCValueDeref(writer, operand);
- try writer.print(".error = {};\n", .{try f.fmtIntLiteral(no_err)});
// Then return the payload pointer (only if it is used)
if (f.liveness.isUnused(inst)) return .none;
- const local = try f.allocLocal(inst, f.typeOfIndex(inst));
+ const local = try f.allocLocal(inst, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = &(");
- try f.writeCValueDeref(writer, operand);
- try writer.writeAll(").payload;\n");
+ try a.assign(f, writer);
+ try writer.writeByte('&');
+ try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
+ try a.end(f, writer);
return local;
}
@@ -5993,14 +6121,14 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
if (!repr_is_err) {
- const a = try Assignment.start(f, writer, payload_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
try a.assign(f, writer);
try f.writeCValue(writer, payload, .Other);
try a.end(f, writer);
}
{
- const a = try Assignment.start(f, writer, err_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
if (repr_is_err)
try f.writeCValue(writer, local, .Other)
else
@@ -6025,7 +6153,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
const payload_ty = err_union_ty.errorUnionPayload(zcu);
const error_ty = err_union_ty.errorUnionSet(zcu);
- const a = try Assignment.start(f, writer, Type.bool);
+ const a = try Assignment.start(f, writer, CType.bool);
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
const err_int_ty = try zcu.errorIntType();
@@ -6062,7 +6190,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
const array_ty = operand_ty.childType(zcu);
{
- const a = try Assignment.start(f, writer, ptr_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
try a.assign(f, writer);
if (operand == .undef) {
@@ -6088,7 +6216,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
try a.end(f, writer);
}
{
- const a = try Assignment.start(f, writer, Type.usize);
+ const a = try Assignment.start(f, writer, CType.usize);
try f.writeCValueMember(writer, local, .{ .identifier = "len" });
try a.assign(f, writer);
try writer.print("{}", .{
@@ -6123,7 +6251,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, writer, operand_ty);
- const a = try Assignment.start(f, writer, scalar_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
try f.writeCValue(writer, local, .Other);
try v.elem(f, writer);
try a.assign(f, writer);
@@ -6165,11 +6293,10 @@ fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(" = (");
try f.renderType(writer, inst_ty);
try writer.writeByte(')');
- if (operand_ty.isSlice(zcu)) {
- try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" });
- } else {
+ if (operand_ty.isSlice(zcu))
+ try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" })
+ else
try f.writeCValue(writer, operand, .Other);
- }
try writer.writeAll(";\n");
return local;
}
@@ -6338,9 +6465,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
const new_value = try f.resolveInst(extra.new_value);
const ptr_ty = f.typeOf(extra.ptr);
const ty = ptr_ty.childType(zcu);
+ const ctype = try f.ctypeFromType(ty, .complete);
const writer = f.object.writer();
- const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value);
+ const new_value_mat = try Materialize.start(f, inst, ty, new_value);
try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
const repr_ty = if (ty.isRuntimeFloat())
@@ -6351,7 +6479,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
const local = try f.allocLocal(inst, inst_ty);
if (inst_ty.isPtrLikeOptional(zcu)) {
{
- const a = try Assignment.start(f, writer, ty);
+ const a = try Assignment.start(f, writer, ctype);
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, expected_value, .Other);
@@ -6381,7 +6509,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
try writer.writeAll(") {\n");
f.object.indent_writer.pushIndent();
{
- const a = try Assignment.start(f, writer, ty);
+ const a = try Assignment.start(f, writer, ctype);
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try writer.writeAll("NULL");
@@ -6391,14 +6519,14 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
try writer.writeAll("}\n");
} else {
{
- const a = try Assignment.start(f, writer, ty);
+ const a = try Assignment.start(f, writer, ctype);
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
try a.assign(f, writer);
try f.writeCValue(writer, expected_value, .Other);
try a.end(f, writer);
}
{
- const a = try Assignment.start(f, writer, Type.bool);
+ const a = try Assignment.start(f, writer, CType.bool);
try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
try a.assign(f, writer);
try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
@@ -6444,7 +6572,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(extra.operand);
const writer = f.object.writer();
- const operand_mat = try Materialize.start(f, inst, writer, ty, operand);
+ const operand_mat = try Materialize.start(f, inst, ty, operand);
try reap(f, inst, &.{ pl_op.operand, extra.operand });
const repr_bits = @as(u16, @intCast(ty.abiSize(zcu) * 8));
@@ -6533,7 +6661,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
const element = try f.resolveInst(bin_op.rhs);
const writer = f.object.writer();
- const element_mat = try Materialize.start(f, inst, writer, ty, element);
+ const element_mat = try Materialize.start(f, inst, ty, element);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const repr_ty = if (ty.isRuntimeFloat())
@@ -6644,7 +6772,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
try f.writeCValue(writer, index, .Other);
try writer.writeAll(") ");
- const a = try Assignment.start(f, writer, elem_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(elem_ty, .complete));
try writer.writeAll("((");
try f.renderType(writer, elem_ptr_ty);
try writer.writeByte(')');
@@ -6669,7 +6797,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
.Slice => {
try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
try writer.writeAll(", ");
- try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
+ try f.writeCValue(writer, bitcasted, .FunctionArgument);
try writer.writeAll(", ");
try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
try writer.writeAll(");\n");
@@ -6680,12 +6808,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
try f.writeCValue(writer, dest_slice, .FunctionArgument);
try writer.writeAll(", ");
- try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);
+ try f.writeCValue(writer, bitcasted, .FunctionArgument);
try writer.print(", {d});\n", .{len});
},
.Many, .C => unreachable,
}
- try bitcasted.free(f);
+ try f.freeCValue(inst, bitcasted);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
@@ -6732,7 +6860,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
const tag_ty = union_ty.unionTagTypeSafety(zcu).?;
const writer = f.object.writer();
- const a = try Assignment.start(f, writer, tag_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" });
try a.assign(f, writer);
try f.writeCValue(writer, new_tag, .Other);
@@ -6754,7 +6882,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, writer, inst_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValueMember(writer, operand, .{ .identifier = "tag" });
@@ -6812,7 +6940,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, writer, inst_ty);
- const a = try Assignment.init(f, inst_scalar_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
try f.writeCValue(writer, local, .Other);
try v.elem(f, writer);
try a.assign(f, writer);
@@ -7065,7 +7193,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const local = try f.allocLocal(inst, inst_ty);
switch (ip.indexToKey(inst_ty.toIntern())) {
inline .array_type, .vector_type => |info, tag| {
- const a = try Assignment.init(f, Type.fromInterned(info.child));
+ const a: Assignment = .{
+ .ctype = try f.ctypeFromType(Type.fromInterned(info.child), .complete),
+ };
for (resolved_elements, 0..) |element, i| {
try a.restart(f, writer);
try f.writeCValue(writer, local, .Other);
@@ -7092,9 +7222,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- const a = try Assignment.start(f, writer, field_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
+ .{ .identifier = field_name.toSlice(ip) }
else
.{ .field = field_index });
try a.assign(f, writer);
@@ -7172,9 +7302,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- const a = try Assignment.start(f, writer, field_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|
- .{ .identifier = ip.stringToSlice(field_name) }
+ .{ .identifier = field_name.toSlice(ip) }
else
.{ .field = field_index });
try a.assign(f, writer);
@@ -7202,13 +7332,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, union_ty);
- if (loaded_union.getLayout(ip) == .@"packed") {
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
- try f.writeCValue(writer, payload, .Initializer);
- try writer.writeAll(";\n");
- return local;
- }
+ if (loaded_union.getLayout(ip) == .@"packed") return f.moveCValue(inst, union_ty, payload);
const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {
const layout = union_ty.unionGetLayout(zcu);
@@ -7216,16 +7340,16 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
const tag_val = try zcu.enumValueFieldIndex(tag_ty, field_index);
- const a = try Assignment.start(f, writer, tag_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
try f.writeCValueMember(writer, local, .{ .identifier = "tag" });
try a.assign(f, writer);
try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, zcu))});
try a.end(f, writer);
}
- break :field .{ .payload_identifier = ip.stringToSlice(field_name) };
- } else .{ .identifier = ip.stringToSlice(field_name) };
+ break :field .{ .payload_identifier = field_name.toSlice(ip) };
+ } else .{ .identifier = field_name.toSlice(ip) };
- const a = try Assignment.start(f, writer, payload_ty);
+ const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
try f.writeCValueMember(writer, local, field);
try a.assign(f, writer);
try f.writeCValue(writer, payload, .Other);
@@ -7680,11 +7804,13 @@ fn StringLiteral(comptime WriterType: type) type {
// MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,
// regardless of the length of the string literal initializing it. Array initializer syntax is
// used instead.
- const max_string_initializer_len = 65535;
+ // C99 only requires 4095.
+ const max_string_initializer_len = @min(65535, 4095);
// MSVC has a length limit of 16380 per string literal (before concatenation)
+ // C99 only requires 4095.
const max_char_len = 4;
- const max_literal_len = 16380 - max_char_len;
+ const max_literal_len = @min(16380 - max_char_len, 4095);
return struct {
len: u64,
@@ -7856,13 +7982,13 @@ fn formatIntLiteral(
} = switch (data.ctype.info(ctype_pool)) {
.basic => |basic_info| switch (basic_info) {
else => .{
- .ctype = .{ .index = .void },
+ .ctype = CType.void,
.count = 1,
.endian = .little,
.homogeneous = true,
},
.zig_u128, .zig_i128 => .{
- .ctype = .{ .index = .uint64_t },
+ .ctype = CType.u64,
.count = 2,
.endian = .big,
.homogeneous = false,
@@ -7978,28 +8104,12 @@ fn formatIntLiteral(
const Materialize = struct {
local: CValue,
- pub fn start(
- f: *Function,
- inst: Air.Inst.Index,
- writer: anytype,
- ty: Type,
- value: CValue,
- ) !Materialize {
- switch (value) {
- .local_ref, .constant, .decl_ref, .undef => {
- const local = try f.allocLocal(inst, ty);
-
- const a = try Assignment.start(f, writer, ty);
- try f.writeCValue(writer, local, .Other);
- try a.assign(f, writer);
- try f.writeCValue(writer, value, .Other);
- try a.end(f, writer);
-
- return .{ .local = local };
- },
- .new_local => |local| return .{ .local = .{ .local = local } },
- else => return .{ .local = value },
- }
+ pub fn start(f: *Function, inst: Air.Inst.Index, ty: Type, value: CValue) !Materialize {
+ return .{ .local = switch (value) {
+ .local_ref, .constant, .decl_ref, .undef => try f.moveCValue(inst, ty, value),
+ .new_local => |local| .{ .local = local },
+ else => value,
+ } };
}
pub fn mat(self: Materialize, f: *Function, writer: anytype) !void {
@@ -8007,22 +8117,15 @@ const Materialize = struct {
}
pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {
- switch (self.local) {
- .new_local => |local| try freeLocal(f, inst, local, null),
- else => {},
- }
+ try f.freeCValue(inst, self.local);
}
};
const Assignment = struct {
ctype: CType,
- pub fn init(f: *Function, ty: Type) !Assignment {
- return .{ .ctype = try f.ctypeFromType(ty, .complete) };
- }
-
- pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {
- const self = try init(f, ty);
+ pub fn start(f: *Function, writer: anytype, ctype: CType) !Assignment {
+ const self: Assignment = .{ .ctype = ctype };
try self.restart(f, writer);
return self;
}
diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig
index 1c460acc6b..357677522c 100644
--- a/src/codegen/c/Type.zig
+++ b/src/codegen/c/Type.zig
@@ -1,13 +1,33 @@
index: CType.Index,
+pub const @"void": CType = .{ .index = .void };
+pub const @"bool": CType = .{ .index = .bool };
+pub const @"i8": CType = .{ .index = .int8_t };
+pub const @"u8": CType = .{ .index = .uint8_t };
+pub const @"i16": CType = .{ .index = .int16_t };
+pub const @"u16": CType = .{ .index = .uint16_t };
+pub const @"i32": CType = .{ .index = .int32_t };
+pub const @"u32": CType = .{ .index = .uint32_t };
+pub const @"i64": CType = .{ .index = .int64_t };
+pub const @"u64": CType = .{ .index = .uint64_t };
+pub const @"i128": CType = .{ .index = .zig_i128 };
+pub const @"u128": CType = .{ .index = .zig_u128 };
+pub const @"isize": CType = .{ .index = .intptr_t };
+pub const @"usize": CType = .{ .index = .uintptr_t };
+pub const @"f16": CType = .{ .index = .zig_f16 };
+pub const @"f32": CType = .{ .index = .zig_f32 };
+pub const @"f64": CType = .{ .index = .zig_f64 };
+pub const @"f80": CType = .{ .index = .zig_f80 };
+pub const @"f128": CType = .{ .index = .zig_f128 };
+
pub fn fromPoolIndex(pool_index: usize) CType {
return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };
}
pub fn toPoolIndex(ctype: CType) ?u32 {
- const pool_index, const is_basic =
+ const pool_index, const is_null =
@subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
- return switch (is_basic) {
+ return switch (is_null) {
0 => pool_index,
1 => null,
};
@@ -710,20 +730,6 @@ pub const Kind = enum {
}
};
-pub const String = struct {
- index: String.Index,
-
- const Index = enum(u32) {
- _,
- };
-
- pub fn slice(string: String, pool: *const Pool) []const u8 {
- const start = pool.string_indices.items[@intFromEnum(string.index)];
- const end = pool.string_indices.items[@intFromEnum(string.index) + 1];
- return pool.string_bytes.items[start..end];
- }
-};
-
pub const Info = union(enum) {
basic: CType.Index,
pointer: Pointer,
@@ -766,7 +772,7 @@ pub const Info = union(enum) {
pub const AggregateTag = enum { @"enum", @"struct", @"union" };
pub const Field = struct {
- name: String,
+ name: Pool.String,
ctype: CType,
alignas: AlignAs,
@@ -812,12 +818,15 @@ pub const Info = union(enum) {
rhs_pool: *const Pool,
pool_adapter: anytype,
) bool {
- return std.meta.eql(lhs_field.alignas, rhs_field.alignas) and
- pool_adapter.eql(lhs_field.ctype, rhs_field.ctype) and std.mem.eql(
- u8,
- lhs_field.name.slice(lhs_pool),
- rhs_field.name.slice(rhs_pool),
- );
+ if (!std.meta.eql(lhs_field.alignas, rhs_field.alignas)) return false;
+ if (!pool_adapter.eql(lhs_field.ctype, rhs_field.ctype)) return false;
+ return if (lhs_field.name.toPoolSlice(lhs_pool)) |lhs_name|
+ if (rhs_field.name.toPoolSlice(rhs_pool)) |rhs_name|
+ std.mem.eql(u8, lhs_name, rhs_name)
+ else
+ false
+ else
+ lhs_field.name.index == rhs_field.name.index;
}
};
@@ -918,6 +927,86 @@ pub const Pool = struct {
const Map = std.AutoArrayHashMapUnmanaged(void, void);
+ pub const String = struct {
+ index: String.Index,
+
+ const FormatData = struct { string: String, pool: *const Pool };
+ fn format(
+ data: FormatData,
+ comptime fmt_str: []const u8,
+ _: std.fmt.FormatOptions,
+ writer: anytype,
+ ) @TypeOf(writer).Error!void {
+ if (fmt_str.len > 0) @compileError("invalid format string '" ++ fmt_str ++ "'");
+ if (data.string.toSlice(data.pool)) |slice|
+ try writer.writeAll(slice)
+ else
+ try writer.print("f{d}", .{@intFromEnum(data.string.index)});
+ }
+ pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(format) {
+ return .{ .data = .{ .string = str, .pool = pool } };
+ }
+
+ fn fromUnnamed(index: u31) String {
+ return .{ .index = @enumFromInt(index) };
+ }
+
+ fn isNamed(str: String) bool {
+ return @intFromEnum(str.index) >= String.Index.first_named_index;
+ }
+
+ pub fn toSlice(str: String, pool: *const Pool) ?[]const u8 {
+ return str.toPoolSlice(pool) orelse if (str.isNamed()) @tagName(str.index) else null;
+ }
+
+ fn toPoolSlice(str: String, pool: *const Pool) ?[]const u8 {
+ if (str.toPoolIndex()) |pool_index| {
+ const start = pool.string_indices.items[pool_index + 0];
+ const end = pool.string_indices.items[pool_index + 1];
+ return pool.string_bytes.items[start..end];
+ } else return null;
+ }
+
+ fn fromPoolIndex(pool_index: usize) String {
+ return .{ .index = @enumFromInt(String.Index.first_pool_index + pool_index) };
+ }
+
+ fn toPoolIndex(str: String) ?u32 {
+ const pool_index, const is_null =
+ @subWithOverflow(@intFromEnum(str.index), String.Index.first_pool_index);
+ return switch (is_null) {
+ 0 => pool_index,
+ 1 => null,
+ };
+ }
+
+ const Index = enum(u32) {
+ array = first_named_index,
+ @"error",
+ is_null,
+ len,
+ payload,
+ ptr,
+ tag,
+ _,
+
+ const first_named_index: u32 = 1 << 31;
+ const first_pool_index: u32 = first_named_index + @typeInfo(String.Index).Enum.fields.len;
+ };
+
+ const Adapter = struct {
+ pool: *const Pool,
+ pub fn hash(_: @This(), slice: []const u8) Map.Hash {
+ return @truncate(Hasher.Impl.hash(1, slice));
+ }
+ pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
+ const rhs_string = String.fromPoolIndex(rhs_index);
+ const rhs_slice = rhs_string.toPoolSlice(string_adapter.pool).?;
+ return std.mem.eql(u8, lhs_slice, rhs_slice);
+ }
+ };
+ };
+
pub const empty: Pool = .{
.map = .{},
.items = .{},
@@ -1200,26 +1289,26 @@ pub const Pool = struct {
kind: Kind,
) !CType {
switch (int_info.bits) {
- 0 => return .{ .index = .void },
+ 0 => return CType.void,
1...8 => switch (int_info.signedness) {
- .unsigned => return .{ .index = .uint8_t },
- .signed => return .{ .index = .int8_t },
+ .signed => return CType.i8,
+ .unsigned => return CType.u8,
},
9...16 => switch (int_info.signedness) {
- .unsigned => return .{ .index = .uint16_t },
- .signed => return .{ .index = .int16_t },
+ .signed => return CType.i16,
+ .unsigned => return CType.u16,
},
17...32 => switch (int_info.signedness) {
- .unsigned => return .{ .index = .uint32_t },
- .signed => return .{ .index = .int32_t },
+ .signed => return CType.i32,
+ .unsigned => return CType.u32,
},
33...64 => switch (int_info.signedness) {
- .unsigned => return .{ .index = .uint64_t },
- .signed => return .{ .index = .int64_t },
+ .signed => return CType.i64,
+ .unsigned => return CType.u64,
},
65...128 => switch (int_info.signedness) {
- .unsigned => return .{ .index = .zig_u128 },
- .signed => return .{ .index = .zig_i128 },
+ .signed => return CType.i128,
+ .unsigned => return CType.u128,
},
else => {
const target = &mod.resolved_target.result;
@@ -1235,7 +1324,7 @@ pub const Pool = struct {
if (!kind.isParameter()) return array_ctype;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "array"),
+ .name = .{ .index = .array },
.ctype = array_ctype,
.alignas = AlignAs.fromAbiAlignment(abi_align),
},
@@ -1267,19 +1356,19 @@ pub const Pool = struct {
.null_type,
.undefined_type,
.enum_literal_type,
- => return .{ .index = .void },
- .u1_type, .u8_type => return .{ .index = .uint8_t },
- .i8_type => return .{ .index = .int8_t },
- .u16_type => return .{ .index = .uint16_t },
- .i16_type => return .{ .index = .int16_t },
- .u29_type, .u32_type => return .{ .index = .uint32_t },
- .i32_type => return .{ .index = .int32_t },
- .u64_type => return .{ .index = .uint64_t },
- .i64_type => return .{ .index = .int64_t },
- .u80_type, .u128_type => return .{ .index = .zig_u128 },
- .i128_type => return .{ .index = .zig_i128 },
- .usize_type => return .{ .index = .uintptr_t },
- .isize_type => return .{ .index = .intptr_t },
+ => return CType.void,
+ .u1_type, .u8_type => return CType.u8,
+ .i8_type => return CType.i8,
+ .u16_type => return CType.u16,
+ .i16_type => return CType.i16,
+ .u29_type, .u32_type => return CType.u32,
+ .i32_type => return CType.i32,
+ .u64_type => return CType.u64,
+ .i64_type => return CType.i64,
+ .u80_type, .u128_type => return CType.u128,
+ .i128_type => return CType.i128,
+ .usize_type => return CType.usize,
+ .isize_type => return CType.isize,
.c_char_type => return .{ .index = .char },
.c_short_type => return .{ .index = .short },
.c_ushort_type => return .{ .index = .@"unsigned short" },
@@ -1290,12 +1379,12 @@ pub const Pool = struct {
.c_longlong_type => return .{ .index = .@"long long" },
.c_ulonglong_type => return .{ .index = .@"unsigned long long" },
.c_longdouble_type => return .{ .index = .@"long double" },
- .f16_type => return .{ .index = .zig_f16 },
- .f32_type => return .{ .index = .zig_f32 },
- .f64_type => return .{ .index = .zig_f64 },
- .f80_type => return .{ .index = .zig_f80 },
- .f128_type => return .{ .index = .zig_f128 },
- .bool_type, .optional_noreturn_type => return .{ .index = .bool },
+ .f16_type => return CType.f16,
+ .f32_type => return CType.f32,
+ .f64_type => return CType.f64,
+ .f80_type => return CType.f80,
+ .f128_type => return CType.f128,
+ .bool_type, .optional_noreturn_type => return CType.bool,
.noreturn_type,
.anyframe_type,
.generic_poison_type,
@@ -1324,17 +1413,17 @@ pub const Pool = struct {
}, mod, kind),
.manyptr_u8_type,
=> return pool.getPointer(allocator, .{
- .elem_ctype = .{ .index = .uint8_t },
+ .elem_ctype = CType.u8,
}),
.manyptr_const_u8_type,
.manyptr_const_u8_sentinel_0_type,
=> return pool.getPointer(allocator, .{
- .elem_ctype = .{ .index = .uint8_t },
+ .elem_ctype = CType.u8,
.@"const" = true,
}),
.single_const_pointer_to_comptime_int_type,
=> return pool.getPointer(allocator, .{
- .elem_ctype = .{ .index = .void },
+ .elem_ctype = CType.void,
.@"const" = true,
}),
.slice_const_u8_type,
@@ -1343,16 +1432,16 @@ pub const Pool = struct {
const target = &mod.resolved_target.result;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "ptr"),
+ .name = .{ .index = .ptr },
.ctype = try pool.getPointer(allocator, .{
- .elem_ctype = .{ .index = .uint8_t },
+ .elem_ctype = CType.u8,
.@"const" = true,
}),
.alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
},
.{
- .name = try pool.string(allocator, "len"),
- .ctype = .{ .index = .uintptr_t },
+ .name = .{ .index = .len },
+ .ctype = CType.usize,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
),
@@ -1442,7 +1531,7 @@ pub const Pool = struct {
const target = &mod.resolved_target.result;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "ptr"),
+ .name = .{ .index = .ptr },
.ctype = try pool.fromType(
allocator,
scratch,
@@ -1454,8 +1543,8 @@ pub const Pool = struct {
.alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
},
.{
- .name = try pool.string(allocator, "len"),
- .ctype = .{ .index = .uintptr_t },
+ .name = .{ .index = .len },
+ .ctype = CType.usize,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
),
@@ -1465,8 +1554,8 @@ pub const Pool = struct {
},
},
.array_type => |array_info| {
- const len = array_info.len + @intFromBool(array_info.sentinel != .none);
- if (len == 0) return .{ .index = .void };
+ const len = array_info.lenIncludingSentinel();
+ if (len == 0) return CType.void;
const elem_type = Type.fromInterned(array_info.child);
const elem_ctype = try pool.fromType(
allocator,
@@ -1476,15 +1565,15 @@ pub const Pool = struct {
mod,
kind.noParameter(),
);
- if (elem_ctype.index == .void) return .{ .index = .void };
+ if (elem_ctype.index == .void) return CType.void;
const array_ctype = try pool.getArray(allocator, .{
.elem_ctype = elem_ctype,
- .len = array_info.len + @intFromBool(array_info.sentinel != .none),
+ .len = len,
});
if (!kind.isParameter()) return array_ctype;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "array"),
+ .name = .{ .index = .array },
.ctype = array_ctype,
.alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
},
@@ -1492,7 +1581,7 @@ pub const Pool = struct {
return pool.fromFields(allocator, .@"struct", &fields, kind);
},
.vector_type => |vector_info| {
- if (vector_info.len == 0) return .{ .index = .void };
+ if (vector_info.len == 0) return CType.void;
const elem_type = Type.fromInterned(vector_info.child);
const elem_ctype = try pool.fromType(
allocator,
@@ -1502,7 +1591,7 @@ pub const Pool = struct {
mod,
kind.noParameter(),
);
- if (elem_ctype.index == .void) return .{ .index = .void };
+ if (elem_ctype.index == .void) return CType.void;
const vector_ctype = try pool.getVector(allocator, .{
.elem_ctype = elem_ctype,
.len = vector_info.len,
@@ -1510,7 +1599,7 @@ pub const Pool = struct {
if (!kind.isParameter()) return vector_ctype;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "array"),
+ .name = .{ .index = .array },
.ctype = vector_ctype,
.alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
},
@@ -1518,7 +1607,7 @@ pub const Pool = struct {
return pool.fromFields(allocator, .@"struct", &fields, kind);
},
.opt_type => |payload_type| {
- if (ip.isNoReturn(payload_type)) return .{ .index = .void };
+ if (ip.isNoReturn(payload_type)) return CType.void;
const payload_ctype = try pool.fromType(
allocator,
scratch,
@@ -1527,7 +1616,7 @@ pub const Pool = struct {
mod,
kind.noParameter(),
);
- if (payload_ctype.index == .void) return .{ .index = .bool };
+ if (payload_ctype.index == .void) return CType.bool;
switch (payload_type) {
.anyerror_type => return payload_ctype,
else => switch (ip.indexToKey(payload_type)) {
@@ -1539,12 +1628,12 @@ pub const Pool = struct {
}
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "is_null"),
- .ctype = .{ .index = .bool },
+ .name = .{ .index = .is_null },
+ .ctype = CType.bool,
.alignas = AlignAs.fromAbiAlignment(.@"1"),
},
.{
- .name = try pool.string(allocator, "payload"),
+ .name = .{ .index = .payload },
.ctype = payload_ctype,
.alignas = AlignAs.fromAbiAlignment(
Type.fromInterned(payload_type).abiAlignment(zcu),
@@ -1574,14 +1663,14 @@ pub const Pool = struct {
const target = &mod.resolved_target.result;
var fields = [_]Info.Field{
.{
- .name = try pool.string(allocator, "error"),
+ .name = .{ .index = .@"error" },
.ctype = error_set_ctype,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(error_set_bits, target.*),
),
},
.{
- .name = try pool.string(allocator, "payload"),
+ .name = .{ .index = .payload },
.ctype = payload_ctype,
.alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
},
@@ -1600,7 +1689,7 @@ pub const Pool = struct {
if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
fwd_decl
else
- .{ .index = .void };
+ CType.void;
const scratch_top = scratch.items.len;
defer scratch.shrinkRetainingCapacity(scratch_top);
try scratch.ensureUnusedCapacity(
@@ -1625,9 +1714,9 @@ pub const Pool = struct {
if (field_ctype.index == .void) continue;
const field_name = if (loaded_struct.fieldName(ip, field_index)
.unwrap()) |field_name|
- try pool.string(allocator, ip.stringToSlice(field_name))
+ try pool.string(allocator, field_name.toSlice(ip))
else
- try pool.fmt(allocator, "f{d}", .{field_index});
+ String.fromUnnamed(@intCast(field_index));
const field_alignas = AlignAs.fromAlignment(.{
.@"align" = loaded_struct.fieldAlign(ip, field_index),
.abi = field_type.abiAlignment(zcu),
@@ -1644,7 +1733,7 @@ pub const Pool = struct {
scratch.items.len - scratch_top,
@typeInfo(Field).Struct.fields.len,
));
- if (fields_len == 0) return .{ .index = .void };
+ if (fields_len == 0) return CType.void;
try pool.ensureUnusedCapacity(allocator, 1);
const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
.fwd_decl = fwd_decl.index,
@@ -1685,7 +1774,7 @@ pub const Pool = struct {
if (field_ctype.index == .void) continue;
const field_name = if (anon_struct_info.fieldName(ip, @intCast(field_index))
.unwrap()) |field_name|
- try pool.string(allocator, ip.stringToSlice(field_name))
+ try pool.string(allocator, field_name.toSlice(ip))
else
try pool.fmt(allocator, "f{d}", .{field_index});
pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
@@ -1700,7 +1789,7 @@ pub const Pool = struct {
scratch.items.len - scratch_top,
@typeInfo(Field).Struct.fields.len,
));
- if (fields_len == 0) return .{ .index = .void };
+ if (fields_len == 0) return CType.void;
if (kind.isForward()) {
try pool.ensureUnusedCapacity(allocator, 1);
const extra_index = try pool.addHashedExtra(
@@ -1739,7 +1828,7 @@ pub const Pool = struct {
if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
fwd_decl
else
- .{ .index = .void };
+ CType.void;
const loaded_tag = loaded_union.loadTagType(ip);
const scratch_top = scratch.items.len;
defer scratch.shrinkRetainingCapacity(scratch_top);
@@ -1766,7 +1855,7 @@ pub const Pool = struct {
if (field_ctype.index == .void) continue;
const field_name = try pool.string(
allocator,
- ip.stringToSlice(loaded_tag.names.get(ip)[field_index]),
+ loaded_tag.names.get(ip)[field_index].toSlice(ip),
);
const field_alignas = AlignAs.fromAlignment(.{
.@"align" = loaded_union.fieldAlign(ip, @intCast(field_index)),
@@ -1786,7 +1875,7 @@ pub const Pool = struct {
@typeInfo(Field).Struct.fields.len,
));
if (!has_tag) {
- if (fields_len == 0) return .{ .index = .void };
+ if (fields_len == 0) return CType.void;
try pool.ensureUnusedCapacity(allocator, 1);
const extra_index = try pool.addHashedExtra(
allocator,
@@ -1813,7 +1902,7 @@ pub const Pool = struct {
);
if (tag_ctype.index != .void) {
struct_fields[struct_fields_len] = .{
- .name = try pool.string(allocator, "tag"),
+ .name = .{ .index = .tag },
.ctype = tag_ctype,
.alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
};
@@ -1846,14 +1935,14 @@ pub const Pool = struct {
};
if (payload_ctype.index != .void) {
struct_fields[struct_fields_len] = .{
- .name = try pool.string(allocator, "payload"),
+ .name = .{ .index = .payload },
.ctype = payload_ctype,
.alignas = AlignAs.fromAbiAlignment(payload_align),
};
struct_fields_len += 1;
}
}
- if (struct_fields_len == 0) return .{ .index = .void };
+ if (struct_fields_len == 0) return CType.void;
sortFields(struct_fields[0..struct_fields_len]);
return pool.getAggregate(allocator, .{
.tag = .@"struct",
@@ -1867,7 +1956,7 @@ pub const Pool = struct {
}, mod, kind),
}
},
- .opaque_type => return .{ .index = .void },
+ .opaque_type => return CType.void,
.enum_type => return pool.fromType(
allocator,
scratch,
@@ -1876,7 +1965,7 @@ pub const Pool = struct {
mod,
kind,
),
- .func_type => |func_info| if (func_info.is_generic) return .{ .index = .void } else {
+ .func_type => |func_info| if (func_info.is_generic) return CType.void else {
const scratch_top = scratch.items.len;
defer scratch.shrinkRetainingCapacity(scratch_top);
try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
@@ -1890,7 +1979,7 @@ pub const Pool = struct {
zcu,
mod,
kind.asParameter(),
- ) else .{ .index = .void };
+ ) else CType.void;
for (0..func_info.param_types.len) |param_index| {
const param_type = Type.fromInterned(
func_info.param_types.get(ip)[param_index],
@@ -2024,7 +2113,10 @@ pub const Pool = struct {
});
for (0..fields.len) |field_index| {
const field = fields.at(field_index, source_pool);
- const field_name = try pool.string(allocator, field.name.slice(source_pool));
+ const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
+ try pool.string(allocator, slice)
+ else
+ field.name;
pool.addExtraAssumeCapacity(Field, .{
.name = field_name.index,
.ctype = pool_adapter.copy(field.ctype).index,
@@ -2054,7 +2146,10 @@ pub const Pool = struct {
});
for (0..aggregate_info.fields.len) |field_index| {
const field = aggregate_info.fields.at(field_index, source_pool);
- const field_name = try pool.string(allocator, field.name.slice(source_pool));
+ const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
+ try pool.string(allocator, slice)
+ else
+ field.name;
pool.addExtraAssumeCapacity(Field, .{
.name = field_name.index,
.ctype = pool_adapter.copy(field.ctype).index,
@@ -2082,8 +2177,8 @@ pub const Pool = struct {
return .{ ctype, gop.found_existing };
}
- pub fn string(pool: *Pool, allocator: std.mem.Allocator, str: []const u8) !String {
- try pool.string_bytes.appendSlice(allocator, str);
+ pub fn string(pool: *Pool, allocator: std.mem.Allocator, slice: []const u8) !String {
+ try pool.string_bytes.appendSlice(allocator, slice);
return pool.trailingString(allocator);
}
@@ -2111,12 +2206,15 @@ pub const Pool = struct {
fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {
inline for (@typeInfo(Extra).Struct.fields) |field| {
const value = @field(extra, field.name);
- hasher.update(switch (field.type) {
+ switch (field.type) {
Pool.Tag, String, CType => unreachable,
- CType.Index => (CType{ .index = value }).hash(pool),
- String.Index => (String{ .index = value }).slice(pool),
- else => value,
- });
+ CType.Index => hasher.update((CType{ .index = value }).hash(pool)),
+ String.Index => if ((String{ .index = value }).toPoolSlice(pool)) |slice|
+ hasher.update(slice)
+ else
+ hasher.update(@intFromEnum(value)),
+ else => hasher.update(value),
+ }
}
}
fn update(hasher: *Hasher, data: anytype) void {
@@ -2231,30 +2329,30 @@ pub const Pool = struct {
}
fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
- const StringAdapter = struct {
- pool: *const Pool,
- pub fn hash(_: @This(), slice: []const u8) Map.Hash {
- return @truncate(Hasher.Impl.hash(1, slice));
- }
- pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
- const rhs_string: String = .{ .index = @enumFromInt(rhs_index) };
- const rhs_slice = rhs_string.slice(string_adapter.pool);
- return std.mem.eql(u8, lhs_slice, rhs_slice);
- }
- };
+ const start = pool.string_indices.getLast();
+ const slice: []const u8 = pool.string_bytes.items[start..];
+ if (slice.len >= 2 and slice[0] == 'f' and switch (slice[1]) {
+ '0' => slice.len == 2,
+ '1'...'9' => true,
+ else => false,
+ }) if (std.fmt.parseInt(u31, slice[1..], 10)) |unnamed| {
+ pool.string_bytes.shrinkRetainingCapacity(start);
+ return String.fromUnnamed(unnamed);
+ } else |_| {};
+ if (std.meta.stringToEnum(String.Index, slice)) |index| {
+ pool.string_bytes.shrinkRetainingCapacity(start);
+ return .{ .index = index };
+ }
+
try pool.string_map.ensureUnusedCapacity(allocator, 1);
try pool.string_indices.ensureUnusedCapacity(allocator, 1);
- const start = pool.string_indices.getLast();
- const gop = pool.string_map.getOrPutAssumeCapacityAdapted(
- @as([]const u8, pool.string_bytes.items[start..]),
- StringAdapter{ .pool = pool },
- );
+ const gop = pool.string_map.getOrPutAssumeCapacityAdapted(slice, String.Adapter{ .pool = pool });
if (gop.found_existing)
pool.string_bytes.shrinkRetainingCapacity(start)
else
pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));
- return .{ .index = @enumFromInt(gop.index) };
+ return String.fromPoolIndex(gop.index);
}
const Item = struct {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 7419e778a1..db0eaa3ce5 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1011,7 +1011,7 @@ pub const Object = struct {
llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty);
for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name| {
- const name_string = try o.builder.stringNull(mod.intern_pool.stringToSlice(name));
+ const name_string = try o.builder.stringNull(name.toSlice(&mod.intern_pool));
const name_init = try o.builder.stringConst(name_string);
const name_variable_index =
try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
@@ -1086,7 +1086,7 @@ pub const Object = struct {
for (object.extern_collisions.keys()) |decl_index| {
const global = object.decl_map.get(decl_index) orelse continue;
// Same logic as below but for externs instead of exports.
- const decl_name = object.builder.strtabStringIfExists(mod.intern_pool.stringToSlice(mod.declPtr(decl_index).name)) orelse continue;
+ const decl_name = object.builder.strtabStringIfExists(mod.declPtr(decl_index).name.toSlice(&mod.intern_pool)) orelse continue;
const other_global = object.builder.getGlobal(decl_name) orelse continue;
if (other_global.toConst().getBase(&object.builder) ==
global.toConst().getBase(&object.builder)) continue;
@@ -1116,7 +1116,7 @@ pub const Object = struct {
for (export_list) |exp| {
// Detect if the LLVM global has already been created as an extern. In such
// case, we need to replace all uses of it with this exported global.
- const exp_name = object.builder.strtabStringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
+ const exp_name = object.builder.strtabStringIfExists(exp.opts.name.toSlice(&mod.intern_pool)) orelse continue;
const other_global = object.builder.getGlobal(exp_name) orelse continue;
if (other_global.toConst().getBase(&object.builder) == global_base) continue;
@@ -1442,7 +1442,7 @@ pub const Object = struct {
} }, &o.builder);
}
- if (ip.stringToSliceUnwrap(decl.@"linksection")) |section|
+ if (decl.@"linksection".toSlice(ip)) |section|
function_index.setSection(try o.builder.string(section), &o.builder);
var deinit_wip = true;
@@ -1662,7 +1662,7 @@ pub const Object = struct {
const subprogram = try o.builder.debugSubprogram(
file,
- try o.builder.metadataString(ip.stringToSlice(decl.name)),
+ try o.builder.metadataString(decl.name.toSlice(ip)),
try o.builder.metadataStringFromStrtabString(function_index.name(&o.builder)),
line_number,
line_number + func.lbrace_line,
@@ -1752,6 +1752,7 @@ pub const Object = struct {
.value => |val| return updateExportedValue(self, mod, val, exports),
};
const gpa = mod.gpa;
+ const ip = &mod.intern_pool;
// If the module does not already have the function, we ignore this function call
// because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
const global_index = self.decl_map.get(decl_index) orelse return;
@@ -1759,17 +1760,14 @@ pub const Object = struct {
const comp = mod.comp;
if (decl.isExtern(mod)) {
const decl_name = decl_name: {
- const decl_name = mod.intern_pool.stringToSlice(decl.name);
-
if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) {
- if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
+ if (decl.getOwnedExternFunc(mod).?.lib_name.toSlice(ip)) |lib_name| {
if (!std.mem.eql(u8, lib_name, "c")) {
- break :decl_name try self.builder.strtabStringFmt("{s}|{s}", .{ decl_name, lib_name });
+ break :decl_name try self.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
}
}
}
-
- break :decl_name try self.builder.strtabString(decl_name);
+ break :decl_name try self.builder.strtabString(decl.name.toSlice(ip));
};
if (self.builder.getGlobal(decl_name)) |other_global| {
@@ -1792,9 +1790,7 @@ pub const Object = struct {
if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder);
}
} else if (exports.len != 0) {
- const main_exp_name = try self.builder.strtabString(
- mod.intern_pool.stringToSlice(exports[0].opts.name),
- );
+ const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip));
try global_index.rename(main_exp_name, &self.builder);
if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
@@ -1803,9 +1799,7 @@ pub const Object = struct {
return updateExportedGlobal(self, mod, global_index, exports);
} else {
- const fqn = try self.builder.strtabString(
- mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)),
- );
+ const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
try global_index.rename(fqn, &self.builder);
global_index.setLinkage(.internal, &self.builder);
if (comp.config.dll_export_fns)
@@ -1832,9 +1826,8 @@ pub const Object = struct {
exports: []const *Module.Export,
) link.File.UpdateExportsError!void {
const gpa = mod.gpa;
- const main_exp_name = try o.builder.strtabString(
- mod.intern_pool.stringToSlice(exports[0].opts.name),
- );
+ const ip = &mod.intern_pool;
+ const main_exp_name = try o.builder.strtabString(exports[0].opts.name.toSlice(ip));
const global_index = i: {
const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
if (gop.found_existing) {
@@ -1845,7 +1838,7 @@ pub const Object = struct {
const llvm_addr_space = toLlvmAddressSpace(.generic, o.target);
const variable_index = try o.builder.addVariable(
main_exp_name,
- try o.lowerType(Type.fromInterned(mod.intern_pool.typeOf(exported_value))),
+ try o.lowerType(Type.fromInterned(ip.typeOf(exported_value))),
llvm_addr_space,
);
const global_index = variable_index.ptrConst(&o.builder).global;
@@ -1867,8 +1860,9 @@ pub const Object = struct {
global_index: Builder.Global.Index,
exports: []const *Module.Export,
) link.File.UpdateExportsError!void {
- global_index.setUnnamedAddr(.default, &o.builder);
const comp = mod.comp;
+ const ip = &mod.intern_pool;
+ global_index.setUnnamedAddr(.default, &o.builder);
if (comp.config.dll_export_fns)
global_index.setDllStorageClass(.dllexport, &o.builder);
global_index.setLinkage(switch (exports[0].opts.linkage) {
@@ -1882,7 +1876,7 @@ pub const Object = struct {
.hidden => .hidden,
.protected => .protected,
}, &o.builder);
- if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section|
+ if (exports[0].opts.section.toSlice(ip)) |section|
switch (global_index.ptrConst(&o.builder).kind) {
.variable => |impl_index| impl_index.setSection(
try o.builder.string(section),
@@ -1900,7 +1894,7 @@ pub const Object = struct {
// Until then we iterate over existing aliases and make them point
// to the correct decl, or otherwise add a new alias. Old aliases are leaked.
for (exports[1..]) |exp| {
- const exp_name = try o.builder.strtabString(mod.intern_pool.stringToSlice(exp.opts.name));
+ const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
if (o.builder.getGlobal(exp_name)) |global| {
switch (global.ptrConst(&o.builder).kind) {
.alias => |alias| {
@@ -2013,7 +2007,7 @@ pub const Object = struct {
std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst();
enumerators[i] = try o.builder.debugEnumerator(
- try o.builder.metadataString(ip.stringToSlice(field_name_ip)),
+ try o.builder.metadataString(field_name_ip.toSlice(ip)),
int_info.signedness == .unsigned,
int_info.bits,
bigint,
@@ -2473,7 +2467,7 @@ pub const Object = struct {
offset = field_offset + field_size;
const field_name = if (tuple.names.len != 0)
- ip.stringToSlice(tuple.names.get(ip)[i])
+ tuple.names.get(ip)[i].toSlice(ip)
else
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
defer if (tuple.names.len == 0) gpa.free(field_name);
@@ -2557,10 +2551,10 @@ pub const Object = struct {
const field_offset = ty.structFieldOffset(field_index, mod);
const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
- try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});
+ try ip.getOrPutStringFmt(gpa, "{d}", .{field_index}, .no_embedded_nulls);
fields.appendAssumeCapacity(try o.builder.debugMemberType(
- try o.builder.metadataString(ip.stringToSlice(field_name)),
+ try o.builder.metadataString(field_name.toSlice(ip)),
.none, // File
debug_fwd_ref,
0, // Line
@@ -2655,7 +2649,7 @@ pub const Object = struct {
const field_name = tag_type.names.get(ip)[field_index];
fields.appendAssumeCapacity(try o.builder.debugMemberType(
- try o.builder.metadataString(ip.stringToSlice(field_name)),
+ try o.builder.metadataString(field_name.toSlice(ip)),
.none, // File
debug_union_fwd_ref,
0, // Line
@@ -2827,7 +2821,7 @@ pub const Object = struct {
const mod = o.module;
const decl = mod.declPtr(decl_index);
return o.builder.debugStructType(
- try o.builder.metadataString(mod.intern_pool.stringToSlice(decl.name)), // TODO use fully qualified name
+ try o.builder.metadataString(decl.name.toSlice(&mod.intern_pool)), // TODO use fully qualified name
try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope),
try o.namespaceToDebugScope(decl.src_namespace),
decl.src_line + 1,
@@ -2844,11 +2838,11 @@ pub const Object = struct {
const std_mod = mod.std_mod;
const std_file = (mod.importPkg(std_mod) catch unreachable).file;
- const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin");
+ const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin", .no_embedded_nulls);
const std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace);
const builtin_decl = std_namespace.decls.getKeyAdapted(builtin_str, Module.DeclAdapter{ .zcu = mod }).?;
- const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace");
+ const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace", .no_embedded_nulls);
// buffer is only used for int_type, `builtin` is a struct.
const builtin_ty = mod.declPtr(builtin_decl).val.toType();
const builtin_namespace = mod.namespacePtrUnwrap(builtin_ty.getNamespaceIndex(mod)).?;
@@ -2892,10 +2886,10 @@ pub const Object = struct {
const is_extern = decl.isExtern(zcu);
const function_index = try o.builder.addFunction(
try o.lowerType(zig_fn_type),
- try o.builder.strtabString(ip.stringToSlice(if (is_extern)
+ try o.builder.strtabString((if (is_extern)
decl.name
else
- try decl.fullyQualifiedName(zcu))),
+ try decl.fullyQualifiedName(zcu)).toSlice(ip)),
toLlvmAddressSpace(decl.@"addrspace", target),
);
gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
@@ -2910,9 +2904,9 @@ pub const Object = struct {
if (target.isWasm()) {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("wasm-import-name"),
- .value = try o.builder.string(ip.stringToSlice(decl.name)),
+ .value = try o.builder.string(decl.name.toSlice(ip)),
} }, &o.builder);
- if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(zcu).?.lib_name)) |lib_name| {
+ if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| {
if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("wasm-import-module"),
.value = try o.builder.string(lib_name),
@@ -3108,9 +3102,10 @@ pub const Object = struct {
const is_extern = decl.isExtern(mod);
const variable_index = try o.builder.addVariable(
- try o.builder.strtabString(mod.intern_pool.stringToSlice(
- if (is_extern) decl.name else try decl.fullyQualifiedName(mod),
- )),
+ try o.builder.strtabString((if (is_extern)
+ decl.name
+ else
+ try decl.fullyQualifiedName(mod)).toSlice(&mod.intern_pool)),
try o.lowerType(decl.typeOf(mod)),
toLlvmGlobalAddressSpace(decl.@"addrspace", mod.getTarget()),
);
@@ -3258,7 +3253,7 @@ pub const Object = struct {
};
},
.array_type => |array_type| o.builder.arrayType(
- array_type.len + @intFromBool(array_type.sentinel != .none),
+ array_type.lenIncludingSentinel(),
try o.lowerType(Type.fromInterned(array_type.child)),
),
.vector_type => |vector_type| o.builder.vectorType(
@@ -3335,9 +3330,7 @@ pub const Object = struct {
return int_ty;
}
- const name = try o.builder.string(ip.stringToSlice(
- try mod.declPtr(struct_type.decl.unwrap().?).fullyQualifiedName(mod),
- ));
+ const fqn = try mod.declPtr(struct_type.decl.unwrap().?).fullyQualifiedName(mod);
var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
defer llvm_field_types.deinit(o.gpa);
@@ -3402,7 +3395,7 @@ pub const Object = struct {
);
}
- const ty = try o.builder.opaqueType(name);
+ const ty = try o.builder.opaqueType(try o.builder.string(fqn.toSlice(ip)));
try o.type_map.put(o.gpa, t.toIntern(), ty);
o.builder.namedTypeSetBody(
@@ -3491,9 +3484,7 @@ pub const Object = struct {
return enum_tag_ty;
}
- const name = try o.builder.string(ip.stringToSlice(
- try mod.declPtr(union_obj.decl).fullyQualifiedName(mod),
- ));
+ const fqn = try mod.declPtr(union_obj.decl).fullyQualifiedName(mod);
const aligned_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[layout.most_aligned_field]);
const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty);
@@ -3513,7 +3504,7 @@ pub const Object = struct {
};
if (layout.tag_size == 0) {
- const ty = try o.builder.opaqueType(name);
+ const ty = try o.builder.opaqueType(try o.builder.string(fqn.toSlice(ip)));
try o.type_map.put(o.gpa, t.toIntern(), ty);
o.builder.namedTypeSetBody(
@@ -3541,7 +3532,7 @@ pub const Object = struct {
llvm_fields_len += 1;
}
- const ty = try o.builder.opaqueType(name);
+ const ty = try o.builder.opaqueType(try o.builder.string(fqn.toSlice(ip)));
try o.type_map.put(o.gpa, t.toIntern(), ty);
o.builder.namedTypeSetBody(
@@ -3554,8 +3545,8 @@ pub const Object = struct {
const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
if (!gop.found_existing) {
const decl = mod.declPtr(ip.loadOpaqueType(t.toIntern()).decl);
- const name = try o.builder.string(ip.stringToSlice(try decl.fullyQualifiedName(mod)));
- gop.value_ptr.* = try o.builder.opaqueType(name);
+ const fqn = try decl.fullyQualifiedName(mod);
+ gop.value_ptr.* = try o.builder.opaqueType(try o.builder.string(fqn.toSlice(ip)));
}
return gop.value_ptr.*;
},
@@ -3859,7 +3850,9 @@ pub const Object = struct {
},
.aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
.array_type => |array_type| switch (aggregate.storage) {
- .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
+ .bytes => |bytes| try o.builder.stringConst(try o.builder.string(
+ bytes.toSlice(array_type.lenIncludingSentinel(), ip),
+ )),
.elems => |elems| {
const array_ty = try o.lowerType(ty);
const elem_ty = array_ty.childType(&o.builder);
@@ -3892,8 +3885,7 @@ pub const Object = struct {
},
.repeated_elem => |elem| {
const len: usize = @intCast(array_type.len);
- const len_including_sentinel: usize =
- @intCast(len + @intFromBool(array_type.sentinel != .none));
+ const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel());
const array_ty = try o.lowerType(ty);
const elem_ty = array_ty.childType(&o.builder);
@@ -3942,7 +3934,7 @@ pub const Object = struct {
defer allocator.free(vals);
switch (aggregate.storage) {
- .bytes => |bytes| for (vals, bytes) |*result_val, byte| {
+ .bytes => |bytes| for (vals, bytes.toSlice(vector_type.len, ip)) |*result_val, byte| {
result_val.* = try o.builder.intConst(.i8, byte);
},
.elems => |elems| for (vals, elems) |*result_val, elem| {
@@ -4633,7 +4625,7 @@ pub const Object = struct {
defer wip_switch.finish(&wip);
for (0..enum_type.names.len) |field_index| {
- const name = try o.builder.stringNull(ip.stringToSlice(enum_type.names.get(ip)[field_index]));
+ const name = try o.builder.stringNull(enum_type.names.get(ip)[field_index].toSlice(ip));
const name_init = try o.builder.stringConst(name);
const name_variable_index =
try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
@@ -4693,6 +4685,7 @@ pub const DeclGen = struct {
fn genDecl(dg: *DeclGen) !void {
const o = dg.object;
const zcu = o.module;
+ const ip = &zcu.intern_pool;
const decl = dg.decl;
const decl_index = dg.decl_index;
assert(decl.has_tv);
@@ -4705,7 +4698,7 @@ pub const DeclGen = struct {
decl.getAlignment(zcu).toLlvm(),
&o.builder,
);
- if (zcu.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
+ if (decl.@"linksection".toSlice(ip)) |section|
variable_index.setSection(try o.builder.string(section), &o.builder);
assert(decl.has_tv);
const init_val = if (decl.val.getVariable(zcu)) |decl_var| decl_var.init else init_val: {
@@ -4728,7 +4721,7 @@ pub const DeclGen = struct {
const debug_file = try o.getDebugFile(namespace.file_scope);
const debug_global_var = try o.builder.debugGlobalVar(
- try o.builder.metadataString(zcu.intern_pool.stringToSlice(decl.name)), // Name
+ try o.builder.metadataString(decl.name.toSlice(ip)), // Name
try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
debug_file, // File
debug_file, // Scope
@@ -5156,8 +5149,8 @@ pub const FuncGen = struct {
self.scope = try o.builder.debugSubprogram(
self.file,
- try o.builder.metadataString(zcu.intern_pool.stringToSlice(decl.name)),
- try o.builder.metadataString(zcu.intern_pool.stringToSlice(fqn)),
+ try o.builder.metadataString(decl.name.toSlice(&zcu.intern_pool)),
+ try o.builder.metadataString(fqn.toSlice(&zcu.intern_pool)),
line_number,
line_number + func.lbrace_line,
try o.lowerDebugType(fn_ty),
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 2570343763..53ec59d531 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -1028,39 +1028,30 @@ const DeclGen = struct {
inline .array_type, .vector_type => |array_type, tag| {
const elem_ty = Type.fromInterned(array_type.child);
- const constituents = try self.gpa.alloc(IdRef, @as(u32, @intCast(ty.arrayLenIncludingSentinel(mod))));
+ const constituents = try self.gpa.alloc(IdRef, @intCast(ty.arrayLenIncludingSentinel(mod)));
defer self.gpa.free(constituents);
switch (aggregate.storage) {
.bytes => |bytes| {
// TODO: This is really space inefficient, perhaps there is a better
// way to do it?
- for (bytes, 0..) |byte, i| {
- constituents[i] = try self.constInt(elem_ty, byte, .indirect);
+ for (constituents, bytes.toSlice(constituents.len, ip)) |*constituent, byte| {
+ constituent.* = try self.constInt(elem_ty, byte, .indirect);
}
},
.elems => |elems| {
- for (0..@as(usize, @intCast(array_type.len))) |i| {
- constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect);
+ for (constituents, elems) |*constituent, elem| {
+ constituent.* = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
}
},
.repeated_elem => |elem| {
- const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect);
- for (0..@as(usize, @intCast(array_type.len))) |i| {
- constituents[i] = val_id;
- }
+ @memset(constituents, try self.constant(elem_ty, Value.fromInterned(elem), .indirect));
},
}
switch (tag) {
- inline .array_type => {
- if (array_type.sentinel != .none) {
- const sentinel = Value.fromInterned(array_type.sentinel);
- constituents[constituents.len - 1] = try self.constant(elem_ty, sentinel, .indirect);
- }
- return self.constructArray(ty, constituents);
- },
- inline .vector_type => return self.constructVector(ty, constituents),
+ .array_type => return self.constructArray(ty, constituents),
+ .vector_type => return self.constructVector(ty, constituents),
else => unreachable,
}
},
@@ -1683,9 +1674,9 @@ const DeclGen = struct {
}
const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
- try ip.getOrPutStringFmt(mod.gpa, "{d}", .{field_index});
+ try ip.getOrPutStringFmt(mod.gpa, "{d}", .{field_index}, .no_embedded_nulls);
try member_types.append(try self.resolveType(field_ty, .indirect));
- try member_names.append(ip.stringToSlice(field_name));
+ try member_names.append(field_name.toSlice(ip));
}
const result_id = try self.spv.structType(member_types.items, member_names.items);
@@ -2123,12 +2114,12 @@ const DeclGen = struct {
// Append the actual code into the functions section.
try self.spv.addFunction(spv_decl_index, self.func);
- const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
- try self.spv.debugName(result_id, fqn);
+ const fqn = try decl.fullyQualifiedName(self.module);
+ try self.spv.debugName(result_id, fqn.toSlice(ip));
// Temporarily generate a test kernel declaration if this is a test function.
if (self.module.test_functions.contains(self.decl_index)) {
- try self.generateTestEntryPoint(fqn, spv_decl_index);
+ try self.generateTestEntryPoint(fqn.toSlice(ip), spv_decl_index);
}
},
.global => {
@@ -2152,8 +2143,8 @@ const DeclGen = struct {
.storage_class = final_storage_class,
});
- const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
- try self.spv.debugName(result_id, fqn);
+ const fqn = try decl.fullyQualifiedName(self.module);
+ try self.spv.debugName(result_id, fqn.toSlice(ip));
try self.spv.declareDeclDeps(spv_decl_index, &.{});
},
.invocation_global => {
@@ -2197,8 +2188,8 @@ const DeclGen = struct {
try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
try self.spv.addFunction(spv_decl_index, self.func);
- const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module));
- try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn});
+ const fqn = try decl.fullyQualifiedName(self.module);
+ try self.spv.debugNameFmt(initializer_id, "initializer of {}", .{fqn.fmt(ip)});
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
.id_result_type = ptr_ty_id,
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index aaf840e02c..413294489a 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -1176,9 +1176,9 @@ pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclInd
gop.value_ptr.* = .{};
}
const unnamed_consts = gop.value_ptr;
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
const index = unnamed_consts.items.len;
- const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
+ const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl_name.fmt(&mod.intern_pool), index });
defer gpa.free(sym_name);
const ty = val.typeOf(mod);
const atom_index = switch (try self.lowerConst(sym_name, val, ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) {
@@ -1257,8 +1257,8 @@ pub fn updateDecl(
if (decl.isExtern(mod)) {
// TODO make this part of getGlobalSymbol
const variable = decl.getOwnedVariable(mod).?;
- const name = mod.intern_pool.stringToSlice(decl.name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
+ const name = decl.name.toSlice(&mod.intern_pool);
+ const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const global_index = try self.getGlobalSymbol(name, lib_name);
try self.need_got_table.put(gpa, global_index, {});
return;
@@ -1425,9 +1425,9 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
+ log.debug("updateDeclCode {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits() orelse 0);
const decl_metadata = self.decls.get(decl_index).?;
@@ -1439,7 +1439,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
if (atom.size != 0) {
const sym = atom.getSymbolPtr(self);
- try self.setSymbolName(sym, decl_name);
+ try self.setSymbolName(sym, decl_name.toSlice(&mod.intern_pool));
sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
@@ -1447,7 +1447,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
if (need_realloc) {
const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
- log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
+ log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), sym.value, vaddr });
log.debug(" (required alignment 0x{x}", .{required_alignment});
if (vaddr != sym.value) {
@@ -1463,13 +1463,13 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
self.getAtomPtr(atom_index).size = code_len;
} else {
const sym = atom.getSymbolPtr(self);
- try self.setSymbolName(sym, decl_name);
+ try self.setSymbolName(sym, decl_name.toSlice(&mod.intern_pool));
sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_index + 1));
sym.type = .{ .complex_type = complex_type, .base_type = .NULL };
const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
errdefer self.freeAtom(atom_index);
- log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
+ log.debug("allocated atom for {} at 0x{x}", .{ decl_name.fmt(&mod.intern_pool), vaddr });
self.getAtomPtr(atom_index).size = code_len;
sym.value = vaddr;
@@ -1534,20 +1534,18 @@ pub fn updateExports(
else => std.builtin.CallingConvention.C,
};
const decl_cc = exported_decl.typeOf(mod).fnCallingConvention(mod);
- if (decl_cc == .C and ip.stringEqlSlice(exp.opts.name, "main") and
- comp.config.link_libc)
- {
+ if (decl_cc == .C and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {
mod.stage1_flags.have_c_main = true;
} else if (decl_cc == winapi_cc and target.os.tag == .windows) {
- if (ip.stringEqlSlice(exp.opts.name, "WinMain")) {
+ if (exp.opts.name.eqlSlice("WinMain", ip)) {
mod.stage1_flags.have_winmain = true;
- } else if (ip.stringEqlSlice(exp.opts.name, "wWinMain")) {
+ } else if (exp.opts.name.eqlSlice("wWinMain", ip)) {
mod.stage1_flags.have_wwinmain = true;
- } else if (ip.stringEqlSlice(exp.opts.name, "WinMainCRTStartup")) {
+ } else if (exp.opts.name.eqlSlice("WinMainCRTStartup", ip)) {
mod.stage1_flags.have_winmain_crt_startup = true;
- } else if (ip.stringEqlSlice(exp.opts.name, "wWinMainCRTStartup")) {
+ } else if (exp.opts.name.eqlSlice("wWinMainCRTStartup", ip)) {
mod.stage1_flags.have_wwinmain_crt_startup = true;
- } else if (ip.stringEqlSlice(exp.opts.name, "DllMainCRTStartup")) {
+ } else if (exp.opts.name.eqlSlice("DllMainCRTStartup", ip)) {
mod.stage1_flags.have_dllmain_crt_startup = true;
}
}
@@ -1585,7 +1583,7 @@ pub fn updateExports(
for (exports) |exp| {
log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
- if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {
+ if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {
if (!mem.eql(u8, section_name, ".text")) {
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
gpa,
@@ -1607,7 +1605,7 @@ pub fn updateExports(
continue;
}
- const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
+ const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const sym_index = metadata.getExport(self, exp_name) orelse blk: {
const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
const global = self.globals.items[global_index];
@@ -1646,18 +1644,18 @@ pub fn updateExports(
pub fn deleteDeclExport(
self: *Coff,
decl_index: InternPool.DeclIndex,
- name_ip: InternPool.NullTerminatedString,
+ name: InternPool.NullTerminatedString,
) void {
if (self.llvm_object) |_| return;
const metadata = self.decls.getPtr(decl_index) orelse return;
const mod = self.base.comp.module.?;
- const name = mod.intern_pool.stringToSlice(name_ip);
- const sym_index = metadata.getExportPtr(self, name) orelse return;
+ const name_slice = name.toSlice(&mod.intern_pool);
+ const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
const gpa = self.base.comp.gpa;
const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
const sym = self.getSymbolPtr(sym_loc);
- log.debug("deleting export '{s}'", .{name});
+ log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
sym.* = .{
.name = [_]u8{0} ** 8,
@@ -1669,7 +1667,7 @@ pub fn deleteDeclExport(
};
self.locals_free_list.append(gpa, sym_index.*) catch {};
- if (self.resolver.fetchRemove(name)) |entry| {
+ if (self.resolver.fetchRemove(name_slice)) |entry| {
defer gpa.free(entry.key);
self.globals_free_list.append(gpa, entry.value) catch {};
self.globals.items[entry.value] = .{
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 6a41bb3793..5f82c924c7 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -339,15 +339,14 @@ pub const DeclState = struct {
struct_type.field_names.get(ip),
struct_type.field_types.get(ip),
struct_type.offsets.get(ip),
- ) |field_name_ip, field_ty, field_off| {
+ ) |field_name, field_ty, field_off| {
if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
- const field_name = ip.stringToSlice(field_name_ip);
+ const field_name_slice = field_name.toSlice(ip);
// DW.AT.member
- try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
+ try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2);
dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member));
// DW.AT.name, DW.FORM.string
- dbg_info_buffer.appendSliceAssumeCapacity(field_name);
- dbg_info_buffer.appendAssumeCapacity(0);
+ dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]);
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.appendNTimes(0, 4);
@@ -374,14 +373,13 @@ pub const DeclState = struct {
try dbg_info_buffer.append(0);
const enum_type = ip.loadEnumType(ty.ip_index);
- for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {
- const field_name = ip.stringToSlice(field_name_index);
+ for (enum_type.names.get(ip), 0..) |field_name, field_i| {
+ const field_name_slice = field_name.toSlice(ip);
// DW.AT.enumerator
- try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
+ try dbg_info_buffer.ensureUnusedCapacity(field_name_slice.len + 2 + @sizeOf(u64));
dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant));
// DW.AT.name, DW.FORM.string
- dbg_info_buffer.appendSliceAssumeCapacity(field_name);
- dbg_info_buffer.appendAssumeCapacity(0);
+ dbg_info_buffer.appendSliceAssumeCapacity(field_name_slice[0 .. field_name_slice.len + 1]);
// DW.AT.const_value, DW.FORM.data8
const value: u64 = value: {
if (enum_type.values.len == 0) break :value field_i; // auto-numbered
@@ -443,11 +441,11 @@ pub const DeclState = struct {
for (union_obj.field_types.get(ip), union_obj.loadTagType(ip).names.get(ip)) |field_ty, field_name| {
if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
+ const field_name_slice = field_name.toSlice(ip);
// DW.AT.member
try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
// DW.AT.name, DW.FORM.string
- try dbg_info_buffer.appendSlice(ip.stringToSlice(field_name));
- try dbg_info_buffer.append(0);
+ try dbg_info_buffer.appendSlice(field_name_slice[0 .. field_name_slice.len + 1]);
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.appendNTimes(0, 4);
@@ -1155,8 +1153,8 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde
dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy);
// .debug_info subprogram
- const decl_name_slice = mod.intern_pool.stringToSlice(decl.name);
- const decl_linkage_name_slice = mod.intern_pool.stringToSlice(decl_linkage_name);
+ const decl_name_slice = decl.name.toSlice(&mod.intern_pool);
+ const decl_linkage_name_slice = decl_linkage_name.toSlice(&mod.intern_pool);
try dbg_info_buffer.ensureUnusedCapacity(1 + ptr_width_bytes + 4 + 4 +
(decl_name_slice.len + 1) + (decl_linkage_name_slice.len + 1));
@@ -2866,15 +2864,14 @@ fn addDbgInfoErrorSetNames(
// DW.AT.const_value, DW.FORM.data8
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian);
- for (error_names) |error_name_ip| {
- const int = try mod.getErrorValue(error_name_ip);
- const error_name = mod.intern_pool.stringToSlice(error_name_ip);
+ for (error_names) |error_name| {
+ const int = try mod.getErrorValue(error_name);
+ const error_name_slice = error_name.toSlice(&mod.intern_pool);
// DW.AT.enumerator
- try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64));
+ try dbg_info_buffer.ensureUnusedCapacity(error_name_slice.len + 2 + @sizeOf(u64));
dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.enum_variant));
// DW.AT.name, DW.FORM.string
- dbg_info_buffer.appendSliceAssumeCapacity(error_name);
- dbg_info_buffer.appendAssumeCapacity(0);
+ dbg_info_buffer.appendSliceAssumeCapacity(error_name_slice[0 .. error_name_slice.len + 1]);
// DW.AT.const_value, DW.FORM.data8
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), int, target_endian);
}
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index c20a4b6afa..03451d140e 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1517,7 +1517,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
if (self.base.isStatic()) {
try argv.append("-static");
- } else if (self.base.isDynLib()) {
+ } else if (self.isEffectivelyDynLib()) {
try argv.append("-shared");
}
@@ -1997,7 +1997,7 @@ fn markImportsExports(self: *Elf) void {
}
if (file_ptr.index() == file_index) {
global.flags.@"export" = true;
- if (elf_file.base.isDynLib() and vis != .PROTECTED) {
+ if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
global.flags.import = true;
}
}
@@ -2005,7 +2005,7 @@ fn markImportsExports(self: *Elf) void {
}
}.mark;
- if (!self.base.isDynLib()) {
+ if (!self.isEffectivelyDynLib()) {
for (self.shared_objects.items) |index| {
for (self.file(index).?.globals()) |global_index| {
const global = self.symbol(global_index);
@@ -2469,7 +2469,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
} else {
try argv.append("-static");
}
- } else if (is_dyn_lib) {
+ } else if (switch (target.os.tag) {
+ else => is_dyn_lib,
+ .haiku => is_exe_or_dyn_lib,
+ }) {
try argv.append("-shared");
}
@@ -2925,7 +2928,7 @@ pub fn writeElfHeader(self: *Elf) !void {
const output_mode = comp.config.output_mode;
const link_mode = comp.config.link_mode;
const elf_type: elf.ET = switch (output_mode) {
- .Exe => if (comp.config.pie) .DYN else .EXEC,
+ .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC,
.Obj => .REL,
.Lib => switch (link_mode) {
.static => @as(elf.ET, .REL),
@@ -3114,7 +3117,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
}
}
- if (self.getTarget().cpu.arch == .riscv64 and self.base.isDynLib()) {
+ if (self.getTarget().cpu.arch == .riscv64 and self.isEffectivelyDynLib()) {
self.global_pointer_index = try linker_defined.addGlobal("__global_pointer$", self);
}
@@ -3420,7 +3423,7 @@ fn initSyntheticSections(self: *Elf) !void {
});
}
- if (self.base.isDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
+ if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
self.dynstrtab_section_index = try self.addSection(.{
.name = ".dynstr",
.flags = elf.SHF_ALLOC,
@@ -3657,7 +3660,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
try self.dynamic.addNeeded(shared_object, self);
}
- if (self.base.isDynLib()) {
+ if (self.isEffectivelyDynLib()) {
if (self.soname) |soname| {
try self.dynamic.setSoname(soname, self);
}
@@ -5246,6 +5249,16 @@ const CsuObjects = struct {
}
};
+/// If a target compiles other output modes as dynamic libraries,
+/// this function returns true for those too.
+pub fn isEffectivelyDynLib(self: Elf) bool {
+ if (self.base.isDynLib()) return true;
+ return switch (self.getTarget().os.tag) {
+ .haiku => self.base.isExe(),
+ else => false,
+ };
+}
+
pub fn isZigSection(self: Elf, shndx: u32) bool {
inline for (&[_]?u32{
self.zig_text_section_index,
diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig
index 3db1182696..b5ceeb24b8 100644
--- a/src/link/Elf/Atom.zig
+++ b/src/link/Elf/Atom.zig
@@ -1054,7 +1054,7 @@ const x86_64 = struct {
it: *RelocsIterator,
) !void {
const is_static = elf_file.base.isStatic();
- const is_dyn_lib = elf_file.base.isDynLib();
+ const is_dyn_lib = elf_file.isEffectivelyDynLib();
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
@@ -1599,7 +1599,7 @@ const aarch64 = struct {
_ = it;
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
- const is_dyn_lib = elf_file.base.isDynLib();
+ const is_dyn_lib = elf_file.isEffectivelyDynLib();
switch (r_type) {
.ABS64 => {
diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig
index cc135f2f97..d483540aa6 100644
--- a/src/link/Elf/Object.zig
+++ b/src/link/Elf/Object.zig
@@ -568,7 +568,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
}
const is_import = blk: {
- if (!elf_file.base.isDynLib()) break :blk false;
+ if (!elf_file.isEffectivelyDynLib()) break :blk false;
const vis = @as(elf.STV, @enumFromInt(esym.st_other));
if (vis == .HIDDEN) break :blk false;
break :blk true;
diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig
index 0ddf19cd05..9db17f2f4f 100644
--- a/src/link/Elf/Symbol.zig
+++ b/src/link/Elf/Symbol.zig
@@ -105,6 +105,29 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
return symbol.pltAddress(elf_file);
}
if (symbol.atom(elf_file)) |atom_ptr| {
+ if (!atom_ptr.flags.alive) {
+ if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {
+ const sym_name = symbol.name(elf_file);
+ if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or
+ mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or
+ mem.startsWith(u8, sym_name, ".eh_frame_seg") or
+ symbol.elfSym(elf_file).st_type() == elf.STT_SECTION)
+ {
+ return elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr;
+ }
+
+ if (mem.startsWith(u8, sym_name, "__FRAME_END__") or
+ mem.startsWith(u8, sym_name, "__EH_FRAME_LIST_END__"))
+ {
+ const shdr = elf_file.shdrs.items[elf_file.eh_frame_section_index.?];
+ return shdr.sh_addr + shdr.sh_size;
+ }
+
+ // TODO I think we potentially should error here
+ }
+
+ return 0;
+ }
return atom_ptr.address(elf_file) + symbol.value;
}
return symbol.value;
@@ -432,6 +455,7 @@ pub const Index = u32;
const assert = std.debug.assert;
const elf = std.elf;
+const mem = std.mem;
const std = @import("std");
const synthetic_sections = @import("synthetic_sections.zig");
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig
index 6aede441c8..f65ef43eac 100644
--- a/src/link/Elf/ZigObject.zig
+++ b/src/link/Elf/ZigObject.zig
@@ -367,7 +367,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
}
const is_import = blk: {
- if (!elf_file.base.isDynLib()) break :blk false;
+ if (!elf_file.isEffectivelyDynLib()) break :blk false;
const vis = @as(elf.STV, @enumFromInt(esym.st_other));
if (vis == .HIDDEN) break :blk false;
break :blk true;
@@ -902,9 +902,9 @@ fn updateDeclCode(
const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
+ log.debug("updateDeclCode {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
const required_alignment = decl.getAlignment(mod);
@@ -915,7 +915,7 @@ fn updateDeclCode(
sym.output_section_index = shdr_index;
atom_ptr.output_section_index = shdr_index;
- sym.name_offset = try self.strtab.insert(gpa, decl_name);
+ sym.name_offset = try self.strtab.insert(gpa, decl_name.toSlice(&mod.intern_pool));
atom_ptr.flags.alive = true;
atom_ptr.name_offset = sym.name_offset;
esym.st_name = sym.name_offset;
@@ -932,7 +932,7 @@ fn updateDeclCode(
const need_realloc = code.len > capacity or !required_alignment.check(atom_ptr.value);
if (need_realloc) {
try atom_ptr.grow(elf_file);
- log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
+ log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom_ptr.value });
if (old_vaddr != atom_ptr.value) {
sym.value = 0;
esym.st_value = 0;
@@ -1000,9 +1000,9 @@ fn updateTlv(
const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateTlv {s} ({*})", .{ decl_name, decl });
+ log.debug("updateTlv {} ({*})", .{ decl_name.fmt(&mod.intern_pool), decl });
const required_alignment = decl.getAlignment(mod);
@@ -1014,7 +1014,7 @@ fn updateTlv(
sym.output_section_index = shndx;
atom_ptr.output_section_index = shndx;
- sym.name_offset = try self.strtab.insert(gpa, decl_name);
+ sym.name_offset = try self.strtab.insert(gpa, decl_name.toSlice(&mod.intern_pool));
atom_ptr.flags.alive = true;
atom_ptr.name_offset = sym.name_offset;
esym.st_value = 0;
@@ -1136,8 +1136,8 @@ pub fn updateDecl(
if (decl.isExtern(mod)) {
// Extern variable gets a .got entry only.
const variable = decl.getOwnedVariable(mod).?;
- const name = mod.intern_pool.stringToSlice(decl.name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
+ const name = decl.name.toSlice(&mod.intern_pool);
+ const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;
return;
@@ -1293,9 +1293,9 @@ pub fn lowerUnnamedConst(
}
const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
const index = unnamed_consts.items.len;
- const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
+ const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl_name.fmt(&mod.intern_pool), index });
defer gpa.free(name);
const ty = val.typeOf(mod);
const sym_index = switch (try self.lowerConst(
@@ -1418,7 +1418,7 @@ pub fn updateExports(
for (exports) |exp| {
if (exp.opts.section.unwrap()) |section_name| {
- if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
+ if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
gpa,
@@ -1445,7 +1445,7 @@ pub fn updateExports(
},
};
const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
- const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
+ const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const name_off = try self.strtab.insert(gpa, exp_name);
const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
exp_index.*
@@ -1476,9 +1476,9 @@ pub fn updateDeclLineNumber(
defer tracy.end();
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
+ log.debug("updateDeclLineNumber {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
if (self.dwarf) |*dw| {
try dw.updateDeclLineNumber(mod, decl_index);
@@ -1493,7 +1493,7 @@ pub fn deleteDeclExport(
) void {
const metadata = self.decls.getPtr(decl_index) orelse return;
const mod = elf_file.base.comp.module.?;
- const exp_name = mod.intern_pool.stringToSlice(name);
+ const exp_name = name.toSlice(&mod.intern_pool);
const esym_index = metadata.@"export"(self, exp_name) orelse return;
log.debug("deleting export '{s}'", .{exp_name});
const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig
index 0e7cb90545..2ef7d49540 100644
--- a/src/link/Elf/synthetic_sections.zig
+++ b/src/link/Elf/synthetic_sections.zig
@@ -89,7 +89,7 @@ pub const DynamicSection = struct {
if (elf_file.verneed_section_index != null) nentries += 2; // VERNEED
if (dt.getFlags(elf_file) != null) nentries += 1; // FLAGS
if (dt.getFlags1(elf_file) != null) nentries += 1; // FLAGS_1
- if (!elf_file.base.isDynLib()) nentries += 1; // DEBUG
+ if (!elf_file.isEffectivelyDynLib()) nentries += 1; // DEBUG
nentries += 1; // NULL
return nentries * @sizeOf(elf.Elf64_Dyn);
}
@@ -216,7 +216,7 @@ pub const DynamicSection = struct {
}
// DEBUG
- if (!elf_file.base.isDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 });
+ if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 });
// NULL
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 });
@@ -256,7 +256,7 @@ pub const ZigGotSection = struct {
entry.* = sym_index;
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_zig_got = true;
- if (elf_file.base.isDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
+ if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
zig_got.flags.needs_rela = true;
}
if (symbol.extra(elf_file)) |extra| {
@@ -495,7 +495,7 @@ pub const GotSection = struct {
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_got = true;
if (symbol.flags.import or symbol.isIFunc(elf_file) or
- ((elf_file.base.isDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))
+ ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))
{
got.flags.needs_rela = true;
}
@@ -528,7 +528,7 @@ pub const GotSection = struct {
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_tlsgd = true;
- if (symbol.flags.import or elf_file.base.isDynLib()) got.flags.needs_rela = true;
+ if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
if (symbol.extra(elf_file)) |extra| {
var new_extra = extra;
new_extra.tlsgd = index;
@@ -545,7 +545,7 @@ pub const GotSection = struct {
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_gottp = true;
- if (symbol.flags.import or elf_file.base.isDynLib()) got.flags.needs_rela = true;
+ if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
if (symbol.extra(elf_file)) |extra| {
var new_extra = extra;
new_extra.gottp = index;
@@ -580,7 +580,7 @@ pub const GotSection = struct {
pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
const comp = elf_file.base.comp;
- const is_dyn_lib = elf_file.base.isDynLib();
+ const is_dyn_lib = elf_file.isEffectivelyDynLib();
const apply_relocs = true; // TODO add user option for this
for (got.entries.items) |entry| {
@@ -595,7 +595,7 @@ pub const GotSection = struct {
if (symbol.?.flags.import) break :blk 0;
if (symbol.?.isIFunc(elf_file))
break :blk if (apply_relocs) value else 0;
- if ((elf_file.base.isDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
+ if ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file))
{
break :blk if (apply_relocs) value else 0;
@@ -653,7 +653,7 @@ pub const GotSection = struct {
pub fn addRela(got: GotSection, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
- const is_dyn_lib = elf_file.base.isDynLib();
+ const is_dyn_lib = elf_file.isEffectivelyDynLib();
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));
@@ -683,7 +683,7 @@ pub const GotSection = struct {
});
continue;
}
- if ((elf_file.base.isDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
+ if ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file))
{
elf_file.addRelaDynAssumeCapacity(.{
@@ -758,7 +758,7 @@ pub const GotSection = struct {
pub fn numRela(got: GotSection, elf_file: *Elf) usize {
const comp = elf_file.base.comp;
- const is_dyn_lib = elf_file.base.isDynLib();
+ const is_dyn_lib = elf_file.isEffectivelyDynLib();
var num: usize = 0;
for (got.entries.items) |entry| {
const symbol = switch (entry.tag) {
@@ -767,7 +767,7 @@ pub const GotSection = struct {
};
switch (entry.tag) {
.got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or
- ((elf_file.base.isDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
+ ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file)))
{
num += 1;
diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig
index fb27c96525..bb788fcacc 100644
--- a/src/link/MachO/ZigObject.zig
+++ b/src/link/MachO/ZigObject.zig
@@ -716,8 +716,8 @@ pub fn updateDecl(
if (decl.isExtern(mod)) {
// Extern variable gets a __got entry only
const variable = decl.getOwnedVariable(mod).?;
- const name = mod.intern_pool.stringToSlice(decl.name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
+ const name = decl.name.toSlice(&mod.intern_pool);
+ const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const index = try self.getGlobalSymbol(macho_file, name, lib_name);
const actual_index = self.symbols.items[index];
macho_file.getSymbol(actual_index).flags.needs_got = true;
@@ -786,9 +786,9 @@ fn updateDeclCode(
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
+ log.debug("updateDeclCode {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
const required_alignment = decl.getAlignment(mod);
@@ -800,7 +800,7 @@ fn updateDeclCode(
sym.out_n_sect = sect_index;
atom.out_n_sect = sect_index;
- sym.name = try self.strtab.insert(gpa, decl_name);
+ sym.name = try self.strtab.insert(gpa, decl_name.toSlice(&mod.intern_pool));
atom.flags.alive = true;
atom.name = sym.name;
nlist.n_strx = sym.name;
@@ -819,7 +819,7 @@ fn updateDeclCode(
if (need_realloc) {
try atom.grow(macho_file);
- log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom.value });
+ log.debug("growing {} from 0x{x} to 0x{x}", .{ decl_name.fmt(&mod.intern_pool), old_vaddr, atom.value });
if (old_vaddr != atom.value) {
sym.value = 0;
nlist.n_value = 0;
@@ -870,23 +870,24 @@ fn updateTlv(
) !void {
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateTlv {s} ({*})", .{ decl_name, decl });
+ log.debug("updateTlv {} ({*})", .{ decl_name.fmt(&mod.intern_pool), decl });
+ const decl_name_slice = decl_name.toSlice(&mod.intern_pool);
const required_alignment = decl.getAlignment(mod);
// 1. Lower TLV initializer
const init_sym_index = try self.createTlvInitializer(
macho_file,
- decl_name,
+ decl_name_slice,
required_alignment,
sect_index,
code,
);
// 2. Create TLV descriptor
- try self.createTlvDescriptor(macho_file, sym_index, init_sym_index, decl_name);
+ try self.createTlvDescriptor(macho_file, sym_index, init_sym_index, decl_name_slice);
}
fn createTlvInitializer(
@@ -1073,9 +1074,9 @@ pub fn lowerUnnamedConst(
}
const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
const index = unnamed_consts.items.len;
- const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
+ const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl_name.fmt(&mod.intern_pool), index });
defer gpa.free(name);
const sym_index = switch (try self.lowerConst(
macho_file,
@@ -1199,7 +1200,7 @@ pub fn updateExports(
for (exports) |exp| {
if (exp.opts.section.unwrap()) |section_name| {
- if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
+ if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
gpa,
@@ -1220,7 +1221,7 @@ pub fn updateExports(
continue;
}
- const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
+ const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const global_nlist_index = if (metadata.@"export"(self, exp_name)) |exp_index|
exp_index.*
else blk: {
@@ -1349,13 +1350,12 @@ pub fn deleteDeclExport(
decl_index: InternPool.DeclIndex,
name: InternPool.NullTerminatedString,
) void {
- const metadata = self.decls.getPtr(decl_index) orelse return;
-
const mod = macho_file.base.comp.module.?;
- const exp_name = mod.intern_pool.stringToSlice(name);
- const nlist_index = metadata.@"export"(self, exp_name) orelse return;
- log.debug("deleting export '{s}'", .{exp_name});
+ const metadata = self.decls.getPtr(decl_index) orelse return;
+ const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
+
+ log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
const nlist = &self.symtab.items(.nlist)[nlist_index.*];
self.symtab.items(.size)[nlist_index.*] = 0;
diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig
index d5900d2b16..323cc8c4a9 100644
--- a/src/link/Plan9.zig
+++ b/src/link/Plan9.zig
@@ -477,11 +477,11 @@ pub fn lowerUnnamedConst(self: *Plan9, val: Value, decl_index: InternPool.DeclIn
}
const unnamed_consts = gop.value_ptr;
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
const index = unnamed_consts.items.len;
// name is freed when the unnamed const is freed
- const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
+ const name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl_name.fmt(&mod.intern_pool), index });
const sym_index = try self.allocateSymbolIndex();
const new_atom_idx = try self.createAtom();
@@ -529,7 +529,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
const decl = mod.declPtr(decl_index);
if (decl.isExtern(mod)) {
- log.debug("found extern decl: {s}", .{mod.intern_pool.stringToSlice(decl.name)});
+ log.debug("found extern decl: {}", .{decl.name.fmt(&mod.intern_pool)});
return;
}
const atom_idx = try self.seeDecl(decl_index);
@@ -573,7 +573,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
const sym: aout.Sym = .{
.value = undefined, // the value of stuff gets filled in in flushModule
.type = atom.type,
- .name = try gpa.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),
+ .name = try gpa.dupe(u8, decl.name.toSlice(&mod.intern_pool)),
};
if (atom.sym_index) |s| {
@@ -1013,10 +1013,12 @@ fn addDeclExports(
const atom = self.getAtom(metadata.index);
for (exports) |exp| {
- const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
+ const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
// plan9 does not support custom sections
if (exp.opts.section.unwrap()) |section_name| {
- if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) {
+ if (!section_name.eqlSlice(".text", &mod.intern_pool) and
+ !section_name.eqlSlice(".data", &mod.intern_pool))
+ {
try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
gpa,
mod.declPtr(decl_index).srcLoc(mod),
@@ -1129,19 +1131,21 @@ pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index {
// handle externs here because they might not get updateDecl called on them
const mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const name = mod.intern_pool.stringToSlice(decl.name);
if (decl.isExtern(mod)) {
// this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
- if (std.mem.eql(u8, name, "etext")) {
+ if (decl.name.eqlSlice("etext", &mod.intern_pool)) {
self.etext_edata_end_atom_indices[0] = atom_idx;
- } else if (std.mem.eql(u8, name, "edata")) {
+ } else if (decl.name.eqlSlice("edata", &mod.intern_pool)) {
self.etext_edata_end_atom_indices[1] = atom_idx;
- } else if (std.mem.eql(u8, name, "end")) {
+ } else if (decl.name.eqlSlice("end", &mod.intern_pool)) {
self.etext_edata_end_atom_indices[2] = atom_idx;
}
try self.updateFinish(decl_index);
- log.debug("seeDecl(extern) for {s} (got_addr=0x{x})", .{ name, self.getAtom(atom_idx).getOffsetTableAddress(self) });
- } else log.debug("seeDecl for {s}", .{name});
+ log.debug("seeDecl(extern) for {} (got_addr=0x{x})", .{
+ decl.name.fmt(&mod.intern_pool),
+ self.getAtom(atom_idx).getOffsetTableAddress(self),
+ });
+ } else log.debug("seeDecl for {}", .{decl.name.fmt(&mod.intern_pool)});
return atom_idx;
}
@@ -1393,7 +1397,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
const sym = self.syms.items[atom.sym_index.?];
try self.writeSym(writer, sym);
if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
- for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
+ for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
try self.writeSym(writer, self.syms.items[exp_i]);
};
}
@@ -1440,7 +1444,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
const sym = self.syms.items[atom.sym_index.?];
try self.writeSym(writer, sym);
if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
- for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| {
+ for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
const s = self.syms.items[exp_i];
if (mem.eql(u8, s.name, "_start"))
self.entry_val = s.value;
@@ -1483,25 +1487,25 @@ pub fn getDeclVAddr(
reloc_info: link.File.RelocInfo,
) !u64 {
const mod = self.base.comp.module.?;
+ const ip = &mod.intern_pool;
const decl = mod.declPtr(decl_index);
- log.debug("getDeclVAddr for {s}", .{mod.intern_pool.stringToSlice(decl.name)});
+ log.debug("getDeclVAddr for {}", .{decl.name.fmt(ip)});
if (decl.isExtern(mod)) {
- const extern_name = mod.intern_pool.stringToSlice(decl.name);
- if (std.mem.eql(u8, extern_name, "etext")) {
+ if (decl.name.eqlSlice("etext", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
.addend = reloc_info.addend,
.type = .special_etext,
});
- } else if (std.mem.eql(u8, extern_name, "edata")) {
+ } else if (decl.name.eqlSlice("edata", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
.addend = reloc_info.addend,
.type = .special_edata,
});
- } else if (std.mem.eql(u8, extern_name, "end")) {
+ } else if (decl.name.eqlSlice("end", ip)) {
try self.addReloc(reloc_info.parent_atom_index, .{
.target = undefined,
.offset = reloc_info.offset,
diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig
index 950e0375f0..27c905cc61 100644
--- a/src/link/SpirV.zig
+++ b/src/link/SpirV.zig
@@ -130,7 +130,7 @@ pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, a
const func = module.funcInfo(func_index);
const decl = module.declPtr(func.owner_decl);
- log.debug("lowering function {s}", .{module.intern_pool.stringToSlice(decl.name)});
+ log.debug("lowering function {}", .{decl.name.fmt(&module.intern_pool)});
try self.object.updateFunc(module, func_index, air, liveness);
}
@@ -141,7 +141,7 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: InternPool.DeclInde
}
const decl = module.declPtr(decl_index);
- log.debug("lowering declaration {s}", .{module.intern_pool.stringToSlice(decl.name)});
+ log.debug("lowering declaration {}", .{decl.name.fmt(&module.intern_pool)});
try self.object.updateDecl(module, decl_index);
}
@@ -178,7 +178,7 @@ pub fn updateExports(
for (exports) |exp| {
try self.object.spv.declareEntryPoint(
spv_decl_index,
- mod.intern_pool.stringToSlice(exp.opts.name),
+ exp.opts.name.toSlice(&mod.intern_pool),
execution_model,
);
}
@@ -227,16 +227,24 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
try error_info.appendSlice("zig_errors");
const mod = self.base.comp.module.?;
- for (mod.global_error_set.keys()) |name_nts| {
- const name = mod.intern_pool.stringToSlice(name_nts);
+ for (mod.global_error_set.keys()) |name| {
// Errors can contain pretty much any character - to encode them in a string we must escape
// them somehow. Easiest here is to use some established scheme, one which also preseves the
// name if it contains no strange characters is nice for debugging. URI encoding fits the bill.
// We're using : as separator, which is a reserved character.
- const escaped_name = try std.Uri.escapeString(gpa, name);
- defer gpa.free(escaped_name);
- try error_info.writer().print(":{s}", .{escaped_name});
+ try std.Uri.Component.percentEncode(
+ error_info.writer(),
+ name.toSlice(&mod.intern_pool),
+ struct {
+ fn isValidChar(c: u8) bool {
+ return switch (c) {
+ 0, '%', ':' => false,
+ else => true,
+ };
+ }
+ }.isValidChar,
+ );
}
try spv.sections.debug_strings.emit(gpa, .OpSourceExtension, .{
.extension = error_info.items,
diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig
index 9bf7718d2b..bcd98c3d3c 100644
--- a/src/link/Wasm/ZigObject.zig
+++ b/src/link/Wasm/ZigObject.zig
@@ -258,8 +258,8 @@ pub fn updateDecl(
if (decl.isExtern(mod)) {
const variable = decl.getOwnedVariable(mod).?;
- const name = mod.intern_pool.stringToSlice(decl.name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
+ const name = decl.name.toSlice(&mod.intern_pool);
+ const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
return zig_object.addOrUpdateImport(wasm_file, name, atom.sym_index, lib_name, null);
}
const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
@@ -341,8 +341,8 @@ fn finishUpdateDecl(
const atom_index = decl_info.atom;
const atom = wasm_file.getAtomPtr(atom_index);
const sym = zig_object.symbol(atom.sym_index);
- const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
- sym.name = try zig_object.string_table.insert(gpa, full_name);
+ const full_name = try decl.fullyQualifiedName(mod);
+ sym.name = try zig_object.string_table.insert(gpa, full_name.toSlice(&mod.intern_pool));
try atom.code.appendSlice(gpa, code);
atom.size = @intCast(code.len);
@@ -382,7 +382,7 @@ fn finishUpdateDecl(
// Will be freed upon freeing of decl or after cleanup of Wasm binary.
const full_segment_name = try std.mem.concat(gpa, u8, &.{
segment_name,
- full_name,
+ full_name.toSlice(&mod.intern_pool),
});
errdefer gpa.free(full_segment_name);
sym.tag = .data;
@@ -427,9 +427,9 @@ pub fn getOrCreateAtomForDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_ind
gop.value_ptr.* = .{ .atom = try wasm_file.createAtom(sym_index, zig_object.index) };
const mod = wasm_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const full_name = try decl.fullyQualifiedName(mod);
const sym = zig_object.symbol(sym_index);
- sym.name = try zig_object.string_table.insert(gpa, full_name);
+ sym.name = try zig_object.string_table.insert(gpa, full_name.toSlice(&mod.intern_pool));
}
return gop.value_ptr.atom;
}
@@ -478,9 +478,9 @@ pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, val: Value, d
const parent_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index);
const parent_atom = wasm_file.getAtom(parent_atom_index);
const local_index = parent_atom.locals.items.len;
- const fqn = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
- const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{
- fqn, local_index,
+ const fqn = try decl.fullyQualifiedName(mod);
+ const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{}_{d}", .{
+ fqn.fmt(&mod.intern_pool), local_index,
});
defer gpa.free(name);
@@ -623,11 +623,11 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {
// Addend for each relocation to the table
var addend: u32 = 0;
const mod = wasm_file.base.comp.module.?;
- for (mod.global_error_set.keys()) |error_name_nts| {
+ for (mod.global_error_set.keys()) |error_name| {
const atom = wasm_file.getAtomPtr(atom_index);
- const error_name = mod.intern_pool.stringToSlice(error_name_nts);
- const len: u32 = @intCast(error_name.len + 1); // names are 0-terminated
+ const error_name_slice = error_name.toSlice(&mod.intern_pool);
+ const len: u32 = @intCast(error_name_slice.len + 1); // names are 0-terminated
const slice_ty = Type.slice_const_u8_sentinel_0;
const offset = @as(u32, @intCast(atom.code.items.len));
@@ -646,10 +646,9 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void {
// as we updated the error name table, we now store the actual name within the names atom
try names_atom.code.ensureUnusedCapacity(gpa, len);
- names_atom.code.appendSliceAssumeCapacity(error_name);
- names_atom.code.appendAssumeCapacity(0);
+ names_atom.code.appendSliceAssumeCapacity(error_name_slice[0..len]);
- log.debug("Populated error name: '{s}'", .{error_name});
+ log.debug("Populated error name: '{}'", .{error_name.fmt(&mod.intern_pool)});
}
names_atom.size = addend;
zig_object.error_names_atom = names_atom_index;
@@ -833,8 +832,7 @@ pub fn deleteDeclExport(
) void {
const mod = wasm_file.base.comp.module.?;
const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
- const export_name = mod.intern_pool.stringToSlice(name);
- if (decl_info.@"export"(zig_object, export_name)) |sym_index| {
+ if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
const sym = zig_object.symbol(sym_index);
decl_info.deleteExport(sym_index);
std.debug.assert(zig_object.global_syms.remove(sym.name));
@@ -864,10 +862,10 @@ pub fn updateExports(
const atom = wasm_file.getAtom(atom_index);
const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*;
const gpa = mod.gpa;
- log.debug("Updating exports for decl '{s}'", .{mod.intern_pool.stringToSlice(decl.name)});
+ log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});
for (exports) |exp| {
- if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| {
+ if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
gpa,
decl.srcLoc(mod),
@@ -877,10 +875,8 @@ pub fn updateExports(
continue;
}
- const export_string = mod.intern_pool.stringToSlice(exp.opts.name);
- const sym_index = if (decl_info.@"export"(zig_object, export_string)) |idx|
- idx
- else index: {
+ const export_string = exp.opts.name.toSlice(&mod.intern_pool);
+ const sym_index = if (decl_info.@"export"(zig_object, export_string)) |idx| idx else index: {
const sym_index = try zig_object.allocateSymbol(gpa);
try decl_info.appendExport(gpa, sym_index);
break :index sym_index;
@@ -1089,9 +1085,9 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm_file: *Wasm, inde
pub fn updateDeclLineNumber(zig_object: *ZigObject, mod: *Module, decl_index: InternPool.DeclIndex) !void {
if (zig_object.dwarf) |*dw| {
const decl = mod.declPtr(decl_index);
- const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
+ const decl_name = try decl.fullyQualifiedName(mod);
- log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
+ log.debug("updateDeclLineNumber {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
try dw.updateDeclLineNumber(mod, decl_index);
}
}
diff --git a/src/mutable_value.zig b/src/mutable_value.zig
index 327c354108..f16a8fd3f9 100644
--- a/src/mutable_value.zig
+++ b/src/mutable_value.zig
@@ -73,7 +73,7 @@ pub const MutableValue = union(enum) {
} }),
.bytes => |b| try ip.get(gpa, .{ .aggregate = .{
.ty = b.ty,
- .storage = .{ .bytes = b.data },
+ .storage = .{ .bytes = try ip.getOrPutString(gpa, b.data, .maybe_embedded_nulls) },
} }),
.aggregate => |a| {
const elems = try arena.alloc(InternPool.Index, a.elems.len);
@@ -158,18 +158,18 @@ pub const MutableValue = union(enum) {
},
.aggregate => |agg| switch (agg.storage) {
.bytes => |bytes| {
- assert(bytes.len == ip.aggregateTypeLenIncludingSentinel(agg.ty));
+ const len: usize = @intCast(ip.aggregateTypeLenIncludingSentinel(agg.ty));
assert(ip.childType(agg.ty) == .u8_type);
if (allow_bytes) {
- const arena_bytes = try arena.alloc(u8, bytes.len);
- @memcpy(arena_bytes, bytes);
+ const arena_bytes = try arena.alloc(u8, len);
+ @memcpy(arena_bytes, bytes.toSlice(len, ip));
mv.* = .{ .bytes = .{
.ty = agg.ty,
.data = arena_bytes,
} };
} else {
- const mut_elems = try arena.alloc(MutableValue, bytes.len);
- for (bytes, mut_elems) |b, *mut_elem| {
+ const mut_elems = try arena.alloc(MutableValue, len);
+ for (bytes.toSlice(len, ip), mut_elems) |b, *mut_elem| {
mut_elem.* = .{ .interned = try ip.get(gpa, .{ .int = .{
.ty = .u8_type,
.storage = .{ .u64 = b },
diff --git a/src/print_value.zig b/src/print_value.zig
index 21a322cd63..c021b011c1 100644
--- a/src/print_value.zig
+++ b/src/print_value.zig
@@ -204,26 +204,35 @@ fn printAggregate(
try writer.writeAll(" }");
return;
},
- .Array => if (aggregate.storage == .bytes and aggregate.storage.bytes.len > 0) {
- const skip_terminator = aggregate.storage.bytes[aggregate.storage.bytes.len - 1] == 0;
- const bytes = if (skip_terminator) b: {
- break :b aggregate.storage.bytes[0 .. aggregate.storage.bytes.len - 1];
- } else aggregate.storage.bytes;
- try writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)});
- if (!is_ref) try writer.writeAll(".*");
- return;
- } else if (ty.arrayLen(zcu) == 0) {
- if (is_ref) try writer.writeByte('&');
- return writer.writeAll(".{}");
- } else if (ty.arrayLen(zcu) == 1) one_byte_str: {
- // The repr isn't `bytes`, but we might still be able to print this as a string
- if (ty.childType(zcu).toIntern() != .u8_type) break :one_byte_str;
- const elem_val = Value.fromInterned(aggregate.storage.values()[0]);
- if (elem_val.isUndef(zcu)) break :one_byte_str;
- const byte = elem_val.toUnsignedInt(zcu);
- try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})});
- if (!is_ref) try writer.writeAll(".*");
- return;
+ .Array => {
+ switch (aggregate.storage) {
+ .bytes => |bytes| string: {
+ const len = ty.arrayLenIncludingSentinel(zcu);
+ if (len == 0) break :string;
+ const slice = bytes.toSlice(if (bytes.at(len - 1, ip) == 0) len - 1 else len, ip);
+ try writer.print("\"{}\"", .{std.zig.fmtEscapes(slice)});
+ if (!is_ref) try writer.writeAll(".*");
+ return;
+ },
+ .elems, .repeated_elem => {},
+ }
+ switch (ty.arrayLen(zcu)) {
+ 0 => {
+ if (is_ref) try writer.writeByte('&');
+ return writer.writeAll(".{}");
+ },
+ 1 => one_byte_str: {
+ // The repr isn't `bytes`, but we might still be able to print this as a string
+ if (ty.childType(zcu).toIntern() != .u8_type) break :one_byte_str;
+ const elem_val = Value.fromInterned(aggregate.storage.values()[0]);
+ if (elem_val.isUndef(zcu)) break :one_byte_str;
+ const byte = elem_val.toUnsignedInt(zcu);
+ try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})});
+ if (!is_ref) try writer.writeAll(".*");
+ return;
+ },
+ else => {},
+ }
},
.Vector => if (ty.arrayLen(zcu) == 0) {
if (is_ref) try writer.writeByte('&');
diff --git a/src/target.zig b/src/target.zig
index fa782075c7..3ad36deab2 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -59,10 +59,15 @@ pub fn alwaysSingleThreaded(target: std.Target) bool {
}
pub fn defaultSingleThreaded(target: std.Target) bool {
- return switch (target.cpu.arch) {
- .wasm32, .wasm64 => true,
- else => false,
- };
+ switch (target.cpu.arch) {
+ .wasm32, .wasm64 => return true,
+ else => {},
+ }
+ switch (target.os.tag) {
+ .haiku => return true,
+ else => {},
+ }
+ return false;
}
/// Valgrind supports more, but Zig does not support them yet.
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 16c2060163..bf6b8ec1d8 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -2086,6 +2086,11 @@ fn finishBoolExpr(
}
},
.Pointer => {
+ if (node.tag() == .string_literal) {
+ // @intFromPtr(node) != 0
+ const int_from_ptr = try Tag.int_from_ptr.create(c.arena, node);
+ return Tag.not_equal.create(c.arena, .{ .lhs = int_from_ptr, .rhs = Tag.zero_literal.init() });
+ }
// node != null
return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
},
@@ -5793,7 +5798,12 @@ fn macroIntToBool(c: *Context, node: Node) !Node {
if (isBoolRes(node)) {
return node;
}
-
+ if (node.tag() == .string_literal) {
+ // @intFromPtr(node) != 0
+ const int_from_ptr = try Tag.int_from_ptr.create(c.arena, node);
+ return Tag.not_equal.create(c.arena, .{ .lhs = int_from_ptr, .rhs = Tag.zero_literal.init() });
+ }
+ // node != 0
return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
}
diff --git a/src/type.zig b/src/type.zig
index 8352552463..264125c6d0 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -490,18 +490,10 @@ pub const Type = struct {
};
},
.anyframe_type => true,
- .array_type => |array_type| {
- if (array_type.sentinel != .none) {
- return Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
- } else {
- return array_type.len > 0 and
- try Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
- }
- },
- .vector_type => |vector_type| {
- return vector_type.len > 0 and
- try Type.fromInterned(vector_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
- },
+ .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
+ try Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
+ .vector_type => |vector_type| return vector_type.len > 0 and
+ try Type.fromInterned(vector_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
.opt_type => |child| {
const child_ty = Type.fromInterned(child);
if (child_ty.isNoReturn(mod)) {
@@ -1240,7 +1232,7 @@ pub const Type = struct {
.anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
.array_type => |array_type| {
- const len = array_type.len + @intFromBool(array_type.sentinel != .none);
+ const len = array_type.lenIncludingSentinel();
if (len == 0) return .{ .scalar = 0 };
switch (try Type.fromInterned(array_type.child).abiSizeAdvanced(mod, strat)) {
.scalar => |elem_size| return .{ .scalar = len * elem_size },
@@ -1577,7 +1569,7 @@ pub const Type = struct {
.anyframe_type => return target.ptrBitWidth(),
.array_type => |array_type| {
- const len = array_type.len + @intFromBool(array_type.sentinel != .none);
+ const len = array_type.lenIncludingSentinel();
if (len == 0) return 0;
const elem_ty = Type.fromInterned(array_type.child);
const elem_size = @max(
@@ -1731,7 +1723,7 @@ pub const Type = struct {
.struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
.union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
.array_type => |array_type| {
- if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
+ if (array_type.lenIncludingSentinel() == 0) return true;
return Type.fromInterned(array_type.child).layoutIsResolved(mod);
},
.opt_type => |child| Type.fromInterned(child).layoutIsResolved(mod),
diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm
index 5005c8c79a..c2cfd2fde4 100644
--- a/stage1/zig1.wasm
+++ b/stage1/zig1.wasm
Binary files differ
diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig
index 2f81dbb9fb..7fc3fbbb4a 100644
--- a/test/behavior/abs.zig
+++ b/test/behavior/abs.zig
@@ -214,7 +214,6 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {
}
test "@abs unsigned int vectors" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@@ -274,7 +273,6 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
}
test "@abs float vectors" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index 68239705da..c1ae3b66c6 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -267,7 +267,6 @@ test "arguments to comptime parameters generated in comptime blocks" {
test "forced tail call" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -280,6 +279,8 @@ test "forced tail call" {
}
}
+ if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
+
const S = struct {
fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 {
if (n == 0) return a;
@@ -301,7 +302,6 @@ test "forced tail call" {
test "inline call preserves tail call" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -314,6 +314,8 @@ test "inline call preserves tail call" {
}
}
+ if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
+
const max = std.math.maxInt(u16);
const S = struct {
var a: u16 = 0;
@@ -432,7 +434,6 @@ test "method call as parameter type" {
test "non-anytype generic parameters provide result type" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -463,7 +464,6 @@ test "non-anytype generic parameters provide result type" {
test "argument to generic function has correct result type" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/call_tail.zig b/test/behavior/call_tail.zig
index ccd0d2ad1e..24aab2a01e 100644
--- a/test/behavior/call_tail.zig
+++ b/test/behavior/call_tail.zig
@@ -45,9 +45,10 @@ test "arguments pointed to on stack into tailcall" {
else => {},
}
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
+
var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 };
base = @intFromPtr(&data);
insertionSort(data[0..]);
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index e88a53629e..72e48de104 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -1119,7 +1119,6 @@ fn foobar(func: PFN_void) !void {
}
test "cast function with an opaque parameter" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) {
@@ -1461,6 +1460,7 @@ test "pointer to empty struct literal to mutable slice" {
test "coerce between pointers of compatible differently-named floats" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
@@ -2558,7 +2558,6 @@ test "@intCast vector of signed integer" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
var x: @Vector(4, i32) = .{ 1, 2, 3, 4 };
diff --git a/test/behavior/export_builtin.zig b/test/behavior/export_builtin.zig
index e93dc6107a..25b6e2527e 100644
--- a/test/behavior/export_builtin.zig
+++ b/test/behavior/export_builtin.zig
@@ -5,7 +5,6 @@ const expect = std.testing.expect;
test "exporting enum type and value" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
const S = struct {
const E = enum(c_int) { one, two };
@@ -20,7 +19,6 @@ test "exporting enum type and value" {
test "exporting with internal linkage" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
const S = struct {
fn foo() callconv(.C) void {}
@@ -34,7 +32,6 @@ test "exporting with internal linkage" {
test "exporting using field access" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
const S = struct {
const Inner = struct {
diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig
index 747d62986e..a85f300b10 100644
--- a/test/behavior/extern.zig
+++ b/test/behavior/extern.zig
@@ -16,7 +16,6 @@ test "anyopaque extern symbol" {
export var a_mystery_symbol: i32 = 1234;
test "function extern symbol" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
@@ -30,7 +29,6 @@ export fn a_mystery_function() i32 {
}
test "function extern symbol matches extern decl" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig
index 373a29f844..ab7aca6ed6 100644
--- a/test/behavior/fn.zig
+++ b/test/behavior/fn.zig
@@ -582,7 +582,6 @@ test "pass and return comptime-only types" {
test "pointer to alias behaves same as pointer to function" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
const S = struct {
diff --git a/test/behavior/globals.zig b/test/behavior/globals.zig
index 96987c95df..89dc20c5c7 100644
--- a/test/behavior/globals.zig
+++ b/test/behavior/globals.zig
@@ -7,7 +7,6 @@ test "store to global array" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
try expect(pos[1] == 0.0);
pos = [2]f32{ 0.0, 1.0 };
@@ -19,7 +18,6 @@ test "store to global vector" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
try expect(vpos[1] == 0.0);
vpos = @Vector(2, f32){ 0.0, 1.0 };
@@ -49,7 +47,6 @@ test "global loads can affect liveness" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
const S = struct {
const ByRef = struct {
diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig
index e808710f98..944ec85f85 100644
--- a/test/behavior/optional.zig
+++ b/test/behavior/optional.zig
@@ -55,17 +55,57 @@ fn testNullPtrsEql() !void {
try expect(&number == x);
}
-test "optional with void type" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+test "optional with zero-bit type" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- const Foo = struct {
- x: ?void,
+ const S = struct {
+ fn doTheTest(comptime ZeroBit: type, comptime zero_bit: ZeroBit) !void {
+ const WithRuntime = struct {
+ zero_bit: ZeroBit,
+ runtime: u1,
+ };
+ var with_runtime: WithRuntime = undefined;
+ with_runtime = .{ .zero_bit = zero_bit, .runtime = 0 };
+
+ const Opt = struct { opt: ?ZeroBit };
+ var opt: Opt = .{ .opt = null };
+ try expect(opt.opt == null);
+ try expect(opt.opt != zero_bit);
+ try expect(opt.opt != with_runtime.zero_bit);
+ opt.opt = zero_bit;
+ try expect(opt.opt != null);
+ try expect(opt.opt == zero_bit);
+ try expect(opt.opt == with_runtime.zero_bit);
+ opt = .{ .opt = zero_bit };
+ try expect(opt.opt != null);
+ try expect(opt.opt == zero_bit);
+ try expect(opt.opt == with_runtime.zero_bit);
+ opt.opt = with_runtime.zero_bit;
+ try expect(opt.opt != null);
+ try expect(opt.opt == zero_bit);
+ try expect(opt.opt == with_runtime.zero_bit);
+ opt = .{ .opt = with_runtime.zero_bit };
+ try expect(opt.opt != null);
+ try expect(opt.opt == zero_bit);
+ try expect(opt.opt == with_runtime.zero_bit);
+
+ var two: ?struct { ZeroBit, ZeroBit } = undefined;
+ two = .{ with_runtime.zero_bit, with_runtime.zero_bit };
+ if (!@inComptime()) {
+ try expect(two != null);
+ try expect(two.?[0] == zero_bit);
+ try expect(two.?[0] == with_runtime.zero_bit);
+ try expect(two.?[1] == zero_bit);
+ try expect(two.?[1] == with_runtime.zero_bit);
+ }
+ }
};
- var x = Foo{ .x = null };
- _ = &x;
- try expect(x.x == null);
+
+ try S.doTheTest(void, {});
+ try comptime S.doTheTest(void, {});
+ try S.doTheTest(enum { only }, .only);
+ try comptime S.doTheTest(enum { only }, .only);
}
test "address of unwrap optional" {
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index 423d7f78e8..3556c06f9c 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -1125,12 +1125,13 @@ test "pointer loaded correctly from packed struct" {
}
}
};
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
+
var ram = try RAM.new();
var cpu = try CPU.new(&ram);
try cpu.tick();
diff --git a/test/behavior/undefined.zig b/test/behavior/undefined.zig
index bb8dfda9df..adda49cfe0 100644
--- a/test/behavior/undefined.zig
+++ b/test/behavior/undefined.zig
@@ -101,7 +101,6 @@ test "reslice of undefined global var slice" {
test "returned undef is 0xaa bytes when runtime safety is enabled" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index 43131ae2d4..7cc272fd77 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -1644,7 +1644,6 @@ test "undefined-layout union field pointer has correct alignment" {
}
test "packed union field pointer has correct alignment" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
index eaf09db628..8a23954c76 100644
--- a/test/behavior/vector.zig
+++ b/test/behavior/vector.zig
@@ -1392,7 +1392,6 @@ test "store vector with memset" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) {
switch (builtin.target.cpu.arch) {
diff --git a/test/cases/translate_c/assert_with_strlit.c b/test/cases/translate_c/assert_with_strlit.c
new file mode 100644
index 0000000000..445428bcf1
--- /dev/null
+++ b/test/cases/translate_c/assert_with_strlit.c
@@ -0,0 +1,8 @@
+
+void assert(int x) {}
+#define FOO assert(0 && "error message")
+
+// translate-c
+// c_frontend=clang
+//
+// pub const FOO = assert((@as(c_int, 0) != 0) and (@intFromPtr("error message") != 0));
diff --git a/test/cases/translate_c/strlit_as_bool.c b/test/cases/translate_c/strlit_as_bool.c
new file mode 100644
index 0000000000..4ba0cfe2a4
--- /dev/null
+++ b/test/cases/translate_c/strlit_as_bool.c
@@ -0,0 +1,8 @@
+void foo() { if(0 && "error message") {} }
+
+// translate-c
+// c_frontend=clang
+//
+// pub export fn foo() void {
+// if (false and (@intFromPtr("error message") != 0)) {}
+// }
diff --git a/test/link/bss/build.zig b/test/link/bss/build.zig
index 865af0a488..cbe913781c 100644
--- a/test/link/bss/build.zig
+++ b/test/link/bss/build.zig
@@ -6,7 +6,7 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "bss",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = b.host,
.optimize = .Debug,
});
diff --git a/test/link/common_symbols/build.zig b/test/link/common_symbols/build.zig
index 9b5c9da662..dd093a891a 100644
--- a/test/link/common_symbols/build.zig
+++ b/test/link/common_symbols/build.zig
@@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
});
const test_exe = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
test_exe.linkLibrary(lib_a);
diff --git a/test/link/common_symbols_alignment/build.zig b/test/link/common_symbols_alignment/build.zig
index 63aff339a9..7e732762ef 100644
--- a/test/link/common_symbols_alignment/build.zig
+++ b/test/link/common_symbols_alignment/build.zig
@@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
});
const test_exe = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
test_exe.linkLibrary(lib_a);
diff --git a/test/link/glibc_compat/build.zig b/test/link/glibc_compat/build.zig
index e0cc1a70d8..67a58200c3 100644
--- a/test/link/glibc_compat/build.zig
+++ b/test/link/glibc_compat/build.zig
@@ -21,7 +21,7 @@ pub fn build(b: *std.Build) void {
.{ .arch_os_abi = t },
) catch unreachable),
});
- exe.addCSourceFile(.{ .file = .{ .path = "main.c" } });
+ exe.addCSourceFile(.{ .file = b.path("main.c") });
exe.linkLibC();
// TODO: actually test the output
_ = exe.getEmittedBin();
@@ -45,7 +45,7 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = t,
- .root_source_file = .{ .path = "glibc_runtime_check.zig" },
+ .root_source_file = b.path("glibc_runtime_check.zig"),
.target = target,
});
exe.linkLibC();
diff --git a/test/link/interdependent_static_c_libs/build.zig b/test/link/interdependent_static_c_libs/build.zig
index 01ed218cce..7b84235b0c 100644
--- a/test/link/interdependent_static_c_libs/build.zig
+++ b/test/link/interdependent_static_c_libs/build.zig
@@ -16,24 +16,24 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
.optimize = optimize,
.target = b.host,
});
- lib_a.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &[_][]const u8{} });
- lib_a.addIncludePath(.{ .path = "." });
+ lib_a.addCSourceFile(.{ .file = b.path("a.c"), .flags = &[_][]const u8{} });
+ lib_a.addIncludePath(b.path("."));
const lib_b = b.addStaticLibrary(.{
.name = "b",
.optimize = optimize,
.target = b.host,
});
- lib_b.addCSourceFile(.{ .file = .{ .path = "b.c" }, .flags = &[_][]const u8{} });
- lib_b.addIncludePath(.{ .path = "." });
+ lib_b.addCSourceFile(.{ .file = b.path("b.c"), .flags = &[_][]const u8{} });
+ lib_b.addIncludePath(b.path("."));
const test_exe = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
test_exe.linkLibrary(lib_a);
test_exe.linkLibrary(lib_b);
- test_exe.addIncludePath(.{ .path = "." });
+ test_exe.addIncludePath(b.path("."));
test_step.dependOn(&b.addRunArtifact(test_exe).step);
}
diff --git a/test/link/macho.zig b/test/link/macho.zig
index 9e91e14da3..4fc6f1b5f1 100644
--- a/test/link/macho.zig
+++ b/test/link/macho.zig
@@ -836,9 +836,9 @@ fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
,
.cpp_source_flags = &.{ "-nostdlib++", "-nostdinc++" },
});
- exe.root_module.addSystemIncludePath(.{ .path = b.pathJoin(&.{ sdk, "/usr/include" }) });
- exe.root_module.addIncludePath(.{ .path = b.pathJoin(&.{ sdk, "/usr/include/c++/v1" }) });
- exe.root_module.addObjectFile(.{ .path = b.pathJoin(&.{ sdk, "/usr/lib/libc++.tbd" }) });
+ exe.root_module.addSystemIncludePath(b.path(b.pathJoin(&.{ sdk, "/usr/include" })));
+ exe.root_module.addIncludePath(b.path(b.pathJoin(&.{ sdk, "/usr/include/c++/v1" })));
+ exe.root_module.addObjectFile(b.path(b.pathJoin(&.{ sdk, "/usr/lib/libc++.tbd" })));
const check = exe.checkObject();
check.checkInSymtab();
diff --git a/test/link/static_libs_from_object_files/build.zig b/test/link/static_libs_from_object_files/build.zig
index d0ea78bbd6..dd679e7ef8 100644
--- a/test/link/static_libs_from_object_files/build.zig
+++ b/test/link/static_libs_from_object_files/build.zig
@@ -57,7 +57,7 @@ fn add(b: *Build, test_step: *Step, files: []const LazyPath, optimize: std.built
{
const exe = b.addExecutable(.{
.name = "test1",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.host,
});
@@ -93,7 +93,7 @@ fn add(b: *Build, test_step: *Step, files: []const LazyPath, optimize: std.built
const exe = b.addExecutable(.{
.name = "test2",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = b.host,
.optimize = optimize,
});
@@ -134,7 +134,7 @@ fn add(b: *Build, test_step: *Step, files: []const LazyPath, optimize: std.built
const exe = b.addExecutable(.{
.name = "test3",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = b.host,
.optimize = optimize,
});
diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig
index cd91feae65..34c5818ad8 100644
--- a/test/link/wasm/archive/build.zig
+++ b/test/link/wasm/archive/build.zig
@@ -17,7 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
// and therefore link with its archive file.
const lib = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.strip = false,
diff --git a/test/link/wasm/basic-features/build.zig b/test/link/wasm/basic-features/build.zig
index 6f9e82d09d..87355a5c12 100644
--- a/test/link/wasm/basic-features/build.zig
+++ b/test/link/wasm/basic-features/build.zig
@@ -6,7 +6,7 @@ pub fn build(b: *std.Build) void {
// Library with explicitly set cpu features
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = .Debug,
.target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig
index 3a1592f394..dc7d1bae4b 100644
--- a/test/link/wasm/bss/build.zig
+++ b/test/link/wasm/bss/build.zig
@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
{
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize_mode,
.strip = false,
@@ -64,7 +64,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
{
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib2.zig" },
+ .root_source_file = b.path("lib2.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize_mode,
.strip = false,
diff --git a/test/link/wasm/export-data/build.zig b/test/link/wasm/export-data/build.zig
index 05b2ca161b..7e3c5e5841 100644
--- a/test/link/wasm/export-data/build.zig
+++ b/test/link/wasm/export-data/build.zig
@@ -11,7 +11,7 @@ pub fn build(b: *std.Build) void {
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.optimize = .ReleaseSafe, // to make the output deterministic in address positions
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
});
diff --git a/test/link/wasm/export/build.zig b/test/link/wasm/export/build.zig
index ab2893ce3c..368826843a 100644
--- a/test/link/wasm/export/build.zig
+++ b/test/link/wasm/export/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const no_export = b.addExecutable(.{
.name = "no-export",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
});
@@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const dynamic_export = b.addExecutable(.{
.name = "dynamic",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
});
@@ -36,7 +36,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const force_export = b.addExecutable(.{
.name = "force",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
});
diff --git a/test/link/wasm/extern-mangle/build.zig b/test/link/wasm/extern-mangle/build.zig
index 41a00eefc9..5a4cbc1cda 100644
--- a/test/link/wasm/extern-mangle/build.zig
+++ b/test/link/wasm/extern-mangle/build.zig
@@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
diff --git a/test/link/wasm/extern/build.zig b/test/link/wasm/extern/build.zig
index baa2b6d61e..77dcbc47c5 100644
--- a/test/link/wasm/extern/build.zig
+++ b/test/link/wasm/extern/build.zig
@@ -15,11 +15,11 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const exe = b.addExecutable(.{
.name = "extern",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
});
- exe.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &.{} });
+ exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
exe.use_llvm = false;
exe.use_lld = false;
diff --git a/test/link/wasm/function-table/build.zig b/test/link/wasm/function-table/build.zig
index aca66e4f71..3042ddf5d5 100644
--- a/test/link/wasm/function-table/build.zig
+++ b/test/link/wasm/function-table/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const import_table = b.addExecutable(.{
.name = "import_table",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
@@ -27,7 +27,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const export_table = b.addExecutable(.{
.name = "export_table",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
@@ -39,7 +39,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const regular_table = b.addExecutable(.{
.name = "regular_table",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
});
diff --git a/test/link/wasm/infer-features/build.zig b/test/link/wasm/infer-features/build.zig
index e3fe860f54..e72e3934f7 100644
--- a/test/link/wasm/infer-features/build.zig
+++ b/test/link/wasm/infer-features/build.zig
@@ -13,13 +13,13 @@ pub fn build(b: *std.Build) void {
.os_tag = .freestanding,
}),
});
- c_obj.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &.{} });
+ c_obj.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
// Wasm library that doesn't have any features specified. This will
// infer its featureset from other linked object files.
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = .Debug,
.target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig
index 4fb777e123..2dae6e3f9b 100644
--- a/test/link/wasm/producers/build.zig
+++ b/test/link/wasm/producers/build.zig
@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
.strip = false,
diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig
index 86073ff977..3c8bac3f07 100644
--- a/test/link/wasm/segments/build.zig
+++ b/test/link/wasm/segments/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
.strip = false,
diff --git a/test/link/wasm/shared-memory/build.zig b/test/link/wasm/shared-memory/build.zig
index 0cad2560cb..7807a95a4f 100644
--- a/test/link/wasm/shared-memory/build.zig
+++ b/test/link/wasm/shared-memory/build.zig
@@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {
const exe = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig
index e95c27827e..e42e362880 100644
--- a/test/link/wasm/stack_pointer/build.zig
+++ b/test/link/wasm/stack_pointer/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const lib = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
.strip = false,
diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig
index b62886c74e..46b80dbfe5 100644
--- a/test/link/wasm/type/build.zig
+++ b/test/link/wasm/type/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const exe = b.addExecutable(.{
.name = "lib",
- .root_source_file = .{ .path = "lib.zig" },
+ .root_source_file = b.path("lib.zig"),
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
.optimize = optimize,
.strip = false,
diff --git a/test/standalone/build.zig b/test/standalone/build.zig
index 673a52cedd..b2575bc83e 100644
--- a/test/standalone/build.zig
+++ b/test/standalone/build.zig
@@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void {
}) |tool_src_path| {
const tool = b.addTest(.{
.name = std.fs.path.stem(tool_src_path),
- .root_source_file = .{ .path = tool_src_path },
+ .root_source_file = b.path(tool_src_path),
.optimize = .Debug,
.target = tools_target,
});
diff --git a/test/standalone/c_compiler/build.zig b/test/standalone/c_compiler/build.zig
index 0550ad8cee..a3c842d8d5 100644
--- a/test/standalone/c_compiler/build.zig
+++ b/test/standalone/c_compiler/build.zig
@@ -30,7 +30,7 @@ fn add(
.optimize = optimize,
.target = target,
});
- exe_c.addCSourceFile(.{ .file = .{ .path = "test.c" }, .flags = &[0][]const u8{} });
+ exe_c.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[0][]const u8{} });
exe_c.linkLibC();
const exe_cpp = b.addExecutable(.{
@@ -39,7 +39,7 @@ fn add(
.target = target,
});
b.default_step.dependOn(&exe_cpp.step);
- exe_cpp.addCSourceFile(.{ .file = .{ .path = "test.cpp" }, .flags = &[0][]const u8{} });
+ exe_cpp.addCSourceFile(.{ .file = b.path("test.cpp"), .flags = &[0][]const u8{} });
exe_cpp.linkLibCpp();
switch (target.result.os.tag) {
diff --git a/test/standalone/child_process/build.zig b/test/standalone/child_process/build.zig
index 89558c00e6..35317602b5 100644
--- a/test/standalone/child_process/build.zig
+++ b/test/standalone/child_process/build.zig
@@ -12,14 +12,14 @@ pub fn build(b: *std.Build) void {
const child = b.addExecutable(.{
.name = "child",
- .root_source_file = .{ .path = "child.zig" },
+ .root_source_file = b.path("child.zig"),
.optimize = optimize,
.target = target,
});
const main = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
});
diff --git a/test/standalone/cmakedefine/build.zig b/test/standalone/cmakedefine/build.zig
index 967aa7ecbd..d90441360f 100644
--- a/test/standalone/cmakedefine/build.zig
+++ b/test/standalone/cmakedefine/build.zig
@@ -4,7 +4,7 @@ const ConfigHeader = std.Build.Step.ConfigHeader;
pub fn build(b: *std.Build) void {
const config_header = b.addConfigHeader(
.{
- .style = .{ .cmake = .{ .path = "config.h.in" } },
+ .style = .{ .cmake = b.path("config.h.in") },
.include_path = "config.h",
},
.{
@@ -28,7 +28,7 @@ pub fn build(b: *std.Build) void {
const pwd_sh = b.addConfigHeader(
.{
- .style = .{ .cmake = .{ .path = "pwd.sh.in" } },
+ .style = .{ .cmake = b.path("pwd.sh.in") },
.include_path = "pwd.sh",
},
.{ .DIR = "${PWD}" },
@@ -36,7 +36,7 @@ pub fn build(b: *std.Build) void {
const sigil_header = b.addConfigHeader(
.{
- .style = .{ .cmake = .{ .path = "sigil.h.in" } },
+ .style = .{ .cmake = b.path("sigil.h.in") },
.include_path = "sigil.h",
},
.{},
@@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void {
const stack_header = b.addConfigHeader(
.{
- .style = .{ .cmake = .{ .path = "stack.h.in" } },
+ .style = .{ .cmake = b.path("stack.h.in") },
.include_path = "stack.h",
},
.{
@@ -57,7 +57,7 @@ pub fn build(b: *std.Build) void {
const wrapper_header = b.addConfigHeader(
.{
- .style = .{ .cmake = .{ .path = "wrapper.h.in" } },
+ .style = .{ .cmake = b.path("wrapper.h.in") },
.include_path = "wrapper.h",
},
.{
diff --git a/test/standalone/compiler_rt_panic/build.zig b/test/standalone/compiler_rt_panic/build.zig
index 8ad7732a93..93331a0282 100644
--- a/test/standalone/compiler_rt_panic/build.zig
+++ b/test/standalone/compiler_rt_panic/build.zig
@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
});
exe.linkLibC();
exe.addCSourceFile(.{
- .file = .{ .path = "main.c" },
+ .file = b.path("main.c"),
.flags = &.{},
});
exe.link_gc_sections = false;
diff --git a/test/standalone/dep_diamond/build.zig b/test/standalone/dep_diamond/build.zig
index 9190b29594..b14503e349 100644
--- a/test/standalone/dep_diamond/build.zig
+++ b/test/standalone/dep_diamond/build.zig
@@ -7,21 +7,21 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const shared = b.createModule(.{
- .root_source_file = .{ .path = "shared.zig" },
+ .root_source_file = b.path("shared.zig"),
});
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = b.host,
.optimize = optimize,
});
exe.root_module.addAnonymousImport("foo", .{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
.imports = &.{.{ .name = "shared", .module = shared }},
});
exe.root_module.addAnonymousImport("bar", .{
- .root_source_file = .{ .path = "bar.zig" },
+ .root_source_file = b.path("bar.zig"),
.imports = &.{.{ .name = "shared", .module = shared }},
});
diff --git a/test/standalone/dep_mutually_recursive/build.zig b/test/standalone/dep_mutually_recursive/build.zig
index 04589d9b5b..804abbce18 100644
--- a/test/standalone/dep_mutually_recursive/build.zig
+++ b/test/standalone/dep_mutually_recursive/build.zig
@@ -7,17 +7,17 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const foo = b.createModule(.{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
});
const bar = b.createModule(.{
- .root_source_file = .{ .path = "bar.zig" },
+ .root_source_file = b.path("bar.zig"),
});
foo.addImport("bar", bar);
bar.addImport("foo", foo);
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = b.host,
.optimize = optimize,
});
diff --git a/test/standalone/dep_recursive/build.zig b/test/standalone/dep_recursive/build.zig
index a6334e6a97..0ab732db4b 100644
--- a/test/standalone/dep_recursive/build.zig
+++ b/test/standalone/dep_recursive/build.zig
@@ -7,13 +7,13 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const foo = b.createModule(.{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
});
foo.addImport("foo", foo);
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = b.host,
.optimize = optimize,
});
diff --git a/test/standalone/dep_shared_builtin/build.zig b/test/standalone/dep_shared_builtin/build.zig
index 33d53ad166..de84e2848d 100644
--- a/test/standalone/dep_shared_builtin/build.zig
+++ b/test/standalone/dep_shared_builtin/build.zig
@@ -8,12 +8,12 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = b.host,
.optimize = optimize,
});
exe.root_module.addAnonymousImport("foo", .{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
});
const run = b.addRunArtifact(exe);
diff --git a/test/standalone/dep_triangle/build.zig b/test/standalone/dep_triangle/build.zig
index b155554997..f9f29099d5 100644
--- a/test/standalone/dep_triangle/build.zig
+++ b/test/standalone/dep_triangle/build.zig
@@ -7,17 +7,17 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const shared = b.createModule(.{
- .root_source_file = .{ .path = "shared.zig" },
+ .root_source_file = b.path("shared.zig"),
});
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = b.host,
.optimize = optimize,
});
exe.root_module.addAnonymousImport("foo", .{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
.imports = &.{.{ .name = "shared", .module = shared }},
});
exe.root_module.addImport("shared", shared);
diff --git a/test/standalone/depend_on_main_mod/build.zig b/test/standalone/depend_on_main_mod/build.zig
index bbef64693e..42e96e0aa0 100644
--- a/test/standalone/depend_on_main_mod/build.zig
+++ b/test/standalone/depend_on_main_mod/build.zig
@@ -9,13 +9,13 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "depend_on_main_mod",
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const foo_module = b.addModule("foo", .{
- .root_source_file = .{ .path = "src/foo.zig" },
+ .root_source_file = b.path("src/foo.zig"),
});
foo_module.addImport("root2", &exe.root_module);
diff --git a/test/standalone/dirname/build.zig b/test/standalone/dirname/build.zig
index 272ed54b38..279f66093a 100644
--- a/test/standalone/dirname/build.zig
+++ b/test/standalone/dirname/build.zig
@@ -6,9 +6,7 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test it");
b.default_step = test_step;
- const touch_src = std.Build.LazyPath{
- .path = "touch.zig",
- };
+ const touch_src = b.path("touch.zig");
const touch = b.addExecutable(.{
.name = "touch",
@@ -20,14 +18,14 @@ pub fn build(b: *std.Build) void {
const exists_in = b.addExecutable(.{
.name = "exists_in",
- .root_source_file = .{ .path = "exists_in.zig" },
+ .root_source_file = b.path("exists_in.zig"),
.optimize = .Debug,
.target = target,
});
const has_basename = b.addExecutable(.{
.name = "has_basename",
- .root_source_file = .{ .path = "has_basename.zig" },
+ .root_source_file = b.path("has_basename.zig"),
.optimize = .Debug,
.target = target,
});
diff --git a/test/standalone/embed_generated_file/build.zig b/test/standalone/embed_generated_file/build.zig
index 3f67cdea54..f7430b7716 100644
--- a/test/standalone/embed_generated_file/build.zig
+++ b/test/standalone/embed_generated_file/build.zig
@@ -6,7 +6,7 @@ pub fn build(b: *std.Build) void {
const bootloader = b.addExecutable(.{
.name = "bootloader",
- .root_source_file = .{ .path = "bootloader.zig" },
+ .root_source_file = b.path("bootloader.zig"),
.target = b.resolveTargetQuery(.{
.cpu_arch = .x86,
.os_tag = .freestanding,
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
});
const exe = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = .Debug,
});
exe.root_module.addAnonymousImport("bootloader.elf", .{
diff --git a/test/standalone/empty_env/build.zig b/test/standalone/empty_env/build.zig
index a2fe483128..b8e488f830 100644
--- a/test/standalone/empty_env/build.zig
+++ b/test/standalone/empty_env/build.zig
@@ -14,7 +14,7 @@ pub fn build(b: *std.Build) void {
const main = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = b.host,
.optimize = optimize,
});
diff --git a/test/standalone/extern/build.zig b/test/standalone/extern/build.zig
index 401deb3dc4..878b92ab58 100644
--- a/test/standalone/extern/build.zig
+++ b/test/standalone/extern/build.zig
@@ -5,12 +5,12 @@ pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "exports",
- .root_source_file = .{ .path = "exports.zig" },
+ .root_source_file = b.path("exports.zig"),
.target = b.host,
.optimize = optimize,
});
const main = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
main.addObject(obj);
diff --git a/test/standalone/global_linkage/build.zig b/test/standalone/global_linkage/build.zig
index 13b7fcfa0e..9edbc96129 100644
--- a/test/standalone/global_linkage/build.zig
+++ b/test/standalone/global_linkage/build.zig
@@ -9,20 +9,20 @@ pub fn build(b: *std.Build) void {
const obj1 = b.addStaticLibrary(.{
.name = "obj1",
- .root_source_file = .{ .path = "obj1.zig" },
+ .root_source_file = b.path("obj1.zig"),
.optimize = optimize,
.target = target,
});
const obj2 = b.addStaticLibrary(.{
.name = "obj2",
- .root_source_file = .{ .path = "obj2.zig" },
+ .root_source_file = b.path("obj2.zig"),
.optimize = optimize,
.target = target,
});
const main = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
main.linkLibrary(obj1);
diff --git a/test/standalone/install_headers/build.zig b/test/standalone/install_headers/build.zig
index 4c9bbb501a..889ee717d6 100644
--- a/test/standalone/install_headers/build.zig
+++ b/test/standalone/install_headers/build.zig
@@ -32,7 +32,7 @@ pub fn build(b: *std.Build) void {
\\}
) });
- libfoo.installHeadersDirectory(.{ .path = "include" }, "foo", .{ .exclude_extensions = &.{".ignore_me.h"} });
+ libfoo.installHeadersDirectory(b.path("include"), "foo", .{ .exclude_extensions = &.{".ignore_me.h"} });
libfoo.installHeader(b.addWriteFiles().add("d.h",
\\#define FOO_D "D"
\\
@@ -78,7 +78,7 @@ pub fn build(b: *std.Build) void {
});
const check_exists = b.addExecutable(.{
.name = "check_exists",
- .root_source_file = .{ .path = "check_exists.zig" },
+ .root_source_file = b.path("check_exists.zig"),
.target = b.resolveTargetQuery(.{}),
.optimize = .Debug,
});
diff --git a/test/standalone/install_raw_hex/build.zig b/test/standalone/install_raw_hex/build.zig
index d1ec55ab53..515528534e 100644
--- a/test/standalone/install_raw_hex/build.zig
+++ b/test/standalone/install_raw_hex/build.zig
@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {
const elf = b.addExecutable(.{
.name = "zig-nrf52-blink.elf",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = target,
.optimize = optimize,
});
diff --git a/test/standalone/ios/build.zig b/test/standalone/ios/build.zig
index 356f12a3d9..daabe8990d 100644
--- a/test/standalone/ios/build.zig
+++ b/test/standalone/ios/build.zig
@@ -21,10 +21,10 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
.target = target,
});
- exe.addCSourceFile(.{ .file = .{ .path = "main.m" }, .flags = &.{} });
- exe.addSystemIncludePath(.{ .path = b.pathJoin(&.{ sdk, "/usr/include" }) });
- exe.addSystemFrameworkPath(.{ .path = b.pathJoin(&.{ sdk, "/System/Library/Frameworks" }) });
- exe.addLibraryPath(.{ .path = b.pathJoin(&.{ sdk, "/usr/lib" }) });
+ exe.addCSourceFile(.{ .file = b.path("main.m"), .flags = &.{} });
+ exe.addSystemIncludePath(b.path(b.pathJoin(&.{ sdk, "/usr/include" })));
+ exe.addSystemFrameworkPath(b.path(b.pathJoin(&.{ sdk, "/System/Library/Frameworks" })));
+ exe.addLibraryPath(b.path(b.pathJoin(&.{ sdk, "/usr/lib" })));
exe.linkFramework("Foundation");
exe.linkFramework("UIKit");
exe.linkLibC();
diff --git a/test/standalone/issue_11595/build.zig b/test/standalone/issue_11595/build.zig
index c591b3058b..b6e17f1eef 100644
--- a/test/standalone/issue_11595/build.zig
+++ b/test/standalone/issue_11595/build.zig
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "zigtest",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = target,
.optimize = optimize,
});
diff --git a/test/standalone/issue_12706/build.zig b/test/standalone/issue_12706/build.zig
index 9a80dae256..528eba89d3 100644
--- a/test/standalone/issue_12706/build.zig
+++ b/test/standalone/issue_12706/build.zig
@@ -10,7 +10,7 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
});
diff --git a/test/standalone/issue_339/build.zig b/test/standalone/issue_339/build.zig
index 5dc686a779..6327c5ed97 100644
--- a/test/standalone/issue_339/build.zig
+++ b/test/standalone/issue_339/build.zig
@@ -9,7 +9,7 @@ pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.target = target,
.optimize = optimize,
});
diff --git a/test/standalone/issue_794/build.zig b/test/standalone/issue_794/build.zig
index eb05aa9b4f..d42ff1f304 100644
--- a/test/standalone/issue_794/build.zig
+++ b/test/standalone/issue_794/build.zig
@@ -5,9 +5,9 @@ pub fn build(b: *std.Build) void {
b.default_step = test_step;
const test_artifact = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
});
- test_artifact.addIncludePath(.{ .path = "a_directory" });
+ test_artifact.addIncludePath(b.path("a_directory"));
// TODO: actually check the output
_ = test_artifact.getEmittedBin();
diff --git a/test/standalone/issue_8550/build.zig b/test/standalone/issue_8550/build.zig
index 557019cfdc..a0dea518d6 100644
--- a/test/standalone/issue_8550/build.zig
+++ b/test/standalone/issue_8550/build.zig
@@ -15,12 +15,12 @@ pub fn build(b: *std.Build) !void {
const kernel = b.addExecutable(.{
.name = "kernel",
- .root_source_file = .{ .path = "./main.zig" },
+ .root_source_file = b.path("./main.zig"),
.optimize = optimize,
.target = target,
});
- kernel.addObjectFile(.{ .path = "./boot.S" });
- kernel.setLinkerScript(.{ .path = "./linker.ld" });
+ kernel.addObjectFile(b.path("./boot.S"));
+ kernel.setLinkerScript(b.path("./linker.ld"));
b.installArtifact(kernel);
test_step.dependOn(&kernel.step);
diff --git a/test/standalone/load_dynamic_library/build.zig b/test/standalone/load_dynamic_library/build.zig
index 140f276ebe..27f8f6de7c 100644
--- a/test/standalone/load_dynamic_library/build.zig
+++ b/test/standalone/load_dynamic_library/build.zig
@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
const lib = b.addSharedLibrary(.{
.name = "add",
- .root_source_file = .{ .path = "add.zig" },
+ .root_source_file = b.path("add.zig"),
.version = .{ .major = 1, .minor = 0, .patch = 0 },
.optimize = optimize,
.target = target,
@@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void {
const main = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
});
diff --git a/test/standalone/mix_c_files/build.zig b/test/standalone/mix_c_files/build.zig
index e91f87e132..779d4d030e 100644
--- a/test/standalone/mix_c_files/build.zig
+++ b/test/standalone/mix_c_files/build.zig
@@ -18,11 +18,11 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = b.host,
.optimize = optimize,
});
- exe.addCSourceFile(.{ .file = .{ .path = "test.c" }, .flags = &[_][]const u8{"-std=c11"} });
+ exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[_][]const u8{"-std=c11"} });
exe.linkLibC();
const run_cmd = b.addRunArtifact(exe);
diff --git a/test/standalone/mix_o_files/build.zig b/test/standalone/mix_o_files/build.zig
index aa648145a8..dd8ef9a4c4 100644
--- a/test/standalone/mix_o_files/build.zig
+++ b/test/standalone/mix_o_files/build.zig
@@ -9,7 +9,7 @@ pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "base64",
- .root_source_file = .{ .path = "base64.zig" },
+ .root_source_file = b.path("base64.zig"),
.optimize = optimize,
.target = target,
});
@@ -20,7 +20,7 @@ pub fn build(b: *std.Build) void {
.target = target,
});
exe.addCSourceFile(.{
- .file = .{ .path = "test.c" },
+ .file = b.path("test.c"),
.flags = &[_][]const u8{"-std=c99"},
});
exe.addObject(obj);
diff --git a/test/standalone/pie/build.zig b/test/standalone/pie/build.zig
index 2e9f99ff4b..25ed330abc 100644
--- a/test/standalone/pie/build.zig
+++ b/test/standalone/pie/build.zig
@@ -11,7 +11,7 @@ pub fn build(b: *std.Build) void {
});
const main = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
});
diff --git a/test/standalone/pkg_import/build.zig b/test/standalone/pkg_import/build.zig
index 207f924f9b..4bef1d756f 100644
--- a/test/standalone/pkg_import/build.zig
+++ b/test/standalone/pkg_import/build.zig
@@ -8,11 +8,11 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "test",
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
.optimize = optimize,
.target = b.host,
});
- exe.root_module.addAnonymousImport("my_pkg", .{ .root_source_file = .{ .path = "pkg.zig" } });
+ exe.root_module.addAnonymousImport("my_pkg", .{ .root_source_file = b.path("pkg.zig") });
const run = b.addRunArtifact(exe);
test_step.dependOn(&run.step);
diff --git a/test/standalone/self_exe_symlink/build.zig b/test/standalone/self_exe_symlink/build.zig
index d61d502574..77799cfa00 100644
--- a/test/standalone/self_exe_symlink/build.zig
+++ b/test/standalone/self_exe_symlink/build.zig
@@ -15,14 +15,14 @@ pub fn build(b: *std.Build) void {
const main = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
});
const create_symlink_exe = b.addExecutable(.{
.name = "create-symlink",
- .root_source_file = .{ .path = "create-symlink.zig" },
+ .root_source_file = b.path("create-symlink.zig"),
.optimize = optimize,
.target = target,
});
diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig
index 4d409295e8..2765a2ec07 100644
--- a/test/standalone/shared_library/build.zig
+++ b/test/standalone/shared_library/build.zig
@@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void {
const target = b.host;
const lib = b.addSharedLibrary(.{
.name = "mathtest",
- .root_source_file = .{ .path = "mathtest.zig" },
+ .root_source_file = b.path("mathtest.zig"),
.version = .{ .major = 1, .minor = 0, .patch = 0 },
.target = target,
.optimize = optimize,
@@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
exe.addCSourceFile(.{
- .file = .{ .path = "test.c" },
+ .file = b.path("test.c"),
.flags = &[_][]const u8{"-std=c99"},
});
exe.linkLibrary(lib);
diff --git a/test/standalone/simple/build.zig b/test/standalone/simple/build.zig
index 8bcfbe0fca..c623780fa5 100644
--- a/test/standalone/simple/build.zig
+++ b/test/standalone/simple/build.zig
@@ -42,7 +42,7 @@ pub fn build(b: *std.Build) void {
if (case.is_exe) {
const exe = b.addExecutable(.{
.name = std.fs.path.stem(case.src_path),
- .root_source_file = .{ .path = case.src_path },
+ .root_source_file = b.path(case.src_path),
.optimize = optimize,
.target = resolved_target,
});
@@ -56,7 +56,7 @@ pub fn build(b: *std.Build) void {
if (case.is_test) {
const exe = b.addTest(.{
.name = std.fs.path.stem(case.src_path),
- .root_source_file = .{ .path = case.src_path },
+ .root_source_file = b.path(case.src_path),
.optimize = optimize,
.target = resolved_target,
});
diff --git a/test/standalone/stack_iterator/build.zig b/test/standalone/stack_iterator/build.zig
index 463a533ac4..7041aaa0b8 100644
--- a/test/standalone/stack_iterator/build.zig
+++ b/test/standalone/stack_iterator/build.zig
@@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
{
const exe = b.addExecutable(.{
.name = "unwind_fp",
- .root_source_file = .{ .path = "unwind.zig" },
+ .root_source_file = b.path("unwind.zig"),
.target = target,
.optimize = optimize,
.unwind_tables = if (target.result.isDarwin()) true else null,
@@ -42,7 +42,7 @@ pub fn build(b: *std.Build) void {
{
const exe = b.addExecutable(.{
.name = "unwind_nofp",
- .root_source_file = .{ .path = "unwind.zig" },
+ .root_source_file = b.path("unwind.zig"),
.target = target,
.optimize = optimize,
.unwind_tables = true,
@@ -74,14 +74,14 @@ pub fn build(b: *std.Build) void {
c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)");
c_shared_lib.addCSourceFile(.{
- .file = .{ .path = "shared_lib.c" },
+ .file = b.path("shared_lib.c"),
.flags = &.{"-fomit-frame-pointer"},
});
c_shared_lib.linkLibC();
const exe = b.addExecutable(.{
.name = "shared_lib_unwind",
- .root_source_file = .{ .path = "shared_lib_unwind.zig" },
+ .root_source_file = b.path("shared_lib_unwind.zig"),
.target = target,
.optimize = optimize,
.unwind_tables = if (target.result.isDarwin()) true else null,
diff --git a/test/standalone/static_c_lib/build.zig b/test/standalone/static_c_lib/build.zig
index 244107b0f1..c025aa9b39 100644
--- a/test/standalone/static_c_lib/build.zig
+++ b/test/standalone/static_c_lib/build.zig
@@ -11,15 +11,15 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
.target = b.host,
});
- foo.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &[_][]const u8{} });
- foo.addIncludePath(.{ .path = "." });
+ foo.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &[_][]const u8{} });
+ foo.addIncludePath(b.path("."));
const test_exe = b.addTest(.{
- .root_source_file = .{ .path = "foo.zig" },
+ .root_source_file = b.path("foo.zig"),
.optimize = optimize,
});
test_exe.linkLibrary(foo);
- test_exe.addIncludePath(.{ .path = "." });
+ test_exe.addIncludePath(b.path("."));
test_step.dependOn(&b.addRunArtifact(test_exe).step);
}
diff --git a/test/standalone/strip_empty_loop/build.zig b/test/standalone/strip_empty_loop/build.zig
index 4875bd9128..aadfbd2fc0 100644
--- a/test/standalone/strip_empty_loop/build.zig
+++ b/test/standalone/strip_empty_loop/build.zig
@@ -9,7 +9,7 @@ pub fn build(b: *std.Build) void {
const main = b.addExecutable(.{
.name = "main",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.target = target,
.strip = true,
diff --git a/test/standalone/strip_struct_init/build.zig b/test/standalone/strip_struct_init/build.zig
index 2d903f973a..ef7960d130 100644
--- a/test/standalone/strip_struct_init/build.zig
+++ b/test/standalone/strip_struct_init/build.zig
@@ -7,7 +7,7 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const main = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
.strip = true,
});
diff --git a/test/standalone/test_runner_module_imports/build.zig b/test/standalone/test_runner_module_imports/build.zig
index af8e68d717..cad3b05e08 100644
--- a/test/standalone/test_runner_module_imports/build.zig
+++ b/test/standalone/test_runner_module_imports/build.zig
@@ -2,13 +2,13 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const t = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
- .test_runner = "test_runner/main.zig",
+ .root_source_file = b.path("src/main.zig"),
+ .test_runner = b.path("test_runner/main.zig"),
});
- const module1 = b.createModule(.{ .root_source_file = .{ .path = "module1/main.zig" } });
+ const module1 = b.createModule(.{ .root_source_file = b.path("module1/main.zig") });
const module2 = b.createModule(.{
- .root_source_file = .{ .path = "module2/main.zig" },
+ .root_source_file = b.path("module2/main.zig"),
.imports = &.{.{ .name = "module1", .module = module1 }},
});
diff --git a/test/standalone/test_runner_path/build.zig b/test/standalone/test_runner_path/build.zig
index 352a18efe0..48ca3c19db 100644
--- a/test/standalone/test_runner_path/build.zig
+++ b/test/standalone/test_runner_path/build.zig
@@ -7,9 +7,9 @@ pub fn build(b: *std.Build) void {
b.default_step = test_step;
const test_exe = b.addTest(.{
- .root_source_file = .{ .path = "test.zig" },
+ .root_source_file = b.path("test.zig"),
});
- test_exe.test_runner = "test_runner.zig";
+ test_exe.test_runner = b.path("test_runner.zig");
const test_run = b.addRunArtifact(test_exe);
test_step.dependOn(&test_run.step);
diff --git a/test/standalone/use_alias/build.zig b/test/standalone/use_alias/build.zig
index 0511cd3935..7ee501713c 100644
--- a/test/standalone/use_alias/build.zig
+++ b/test/standalone/use_alias/build.zig
@@ -7,10 +7,10 @@ pub fn build(b: *std.Build) void {
const optimize: std.builtin.OptimizeMode = .Debug;
const main = b.addTest(.{
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.optimize = optimize,
});
- main.addIncludePath(.{ .path = "." });
+ main.addIncludePath(b.path("."));
test_step.dependOn(&b.addRunArtifact(main).step);
}
diff --git a/test/standalone/windows_entry_points/build.zig b/test/standalone/windows_entry_points/build.zig
index 25c4839147..c3d9c49940 100644
--- a/test/standalone/windows_entry_points/build.zig
+++ b/test/standalone/windows_entry_points/build.zig
@@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
.optimize = .Debug,
.link_libc = true,
});
- exe.addCSourceFile(.{ .file = .{ .path = "main.c" } });
+ exe.addCSourceFile(.{ .file = b.path("main.c") });
_ = exe.getEmittedBin();
test_step.dependOn(&exe.step);
@@ -31,7 +31,7 @@ pub fn build(b: *std.Build) void {
.link_libc = true,
});
exe.mingw_unicode_entry_point = true;
- exe.addCSourceFile(.{ .file = .{ .path = "wmain.c" } });
+ exe.addCSourceFile(.{ .file = b.path("wmain.c") });
_ = exe.getEmittedBin();
test_step.dependOn(&exe.step);
@@ -45,7 +45,7 @@ pub fn build(b: *std.Build) void {
.link_libc = true,
});
// Note: `exe.subsystem = .Windows;` is not necessary
- exe.addCSourceFile(.{ .file = .{ .path = "winmain.c" } });
+ exe.addCSourceFile(.{ .file = b.path("winmain.c") });
_ = exe.getEmittedBin();
test_step.dependOn(&exe.step);
@@ -60,7 +60,7 @@ pub fn build(b: *std.Build) void {
});
exe.mingw_unicode_entry_point = true;
// Note: `exe.subsystem = .Windows;` is not necessary
- exe.addCSourceFile(.{ .file = .{ .path = "wwinmain.c" } });
+ exe.addCSourceFile(.{ .file = b.path("wwinmain.c") });
_ = exe.getEmittedBin();
test_step.dependOn(&exe.step);
diff --git a/test/standalone/windows_resources/build.zig b/test/standalone/windows_resources/build.zig
index 5111751571..6a72dee2a6 100644
--- a/test/standalone/windows_resources/build.zig
+++ b/test/standalone/windows_resources/build.zig
@@ -25,12 +25,12 @@ fn add(
) void {
const exe = b.addExecutable(.{
.name = "zig_resource_test",
- .root_source_file = .{ .path = "main.zig" },
+ .root_source_file = b.path("main.zig"),
.target = target,
.optimize = .Debug,
});
exe.addWin32ResourceFile(.{
- .file = .{ .path = "res/zig.rc" },
+ .file = b.path("res/zig.rc"),
.flags = &.{"/c65001"}, // UTF-8 code page
});
exe.rc_includes = switch (rc_includes) {
diff --git a/test/standalone/zerolength_check/build.zig b/test/standalone/zerolength_check/build.zig
index dacfc841c1..8118c6e172 100644
--- a/test/standalone/zerolength_check/build.zig
+++ b/test/standalone/zerolength_check/build.zig
@@ -12,7 +12,7 @@ pub fn build(b: *std.Build) void {
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
const unit_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = b.resolveTargetQuery(.{
.os_tag = .wasi,
.cpu_arch = .wasm32,
diff --git a/test/tests.zig b/test/tests.zig
index 286ac7e91c..d18958cfc6 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -641,7 +641,7 @@ pub fn addStackTraceTests(
) *Step {
const check_exe = b.addExecutable(.{
.name = "check-stack-trace",
- .root_source_file = .{ .path = "test/src/check-stack-trace.zig" },
+ .root_source_file = b.path("test/src/check-stack-trace.zig"),
.target = b.host,
.optimize = .Debug,
});
@@ -879,7 +879,7 @@ pub fn addCliTests(b: *std.Build) *Step {
run6.step.dependOn(&write6.step);
// TODO change this to an exact match
- const check6 = b.addCheckFile(.{ .path = fmt6_path }, .{
+ const check6 = b.addCheckFile(.{ .cwd_relative = fmt6_path }, .{
.expected_matches = &.{
"// no reason",
},
@@ -1037,7 +1037,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
options.max_rss;
const these_tests = b.addTest(.{
- .root_source_file = .{ .path = options.root_src },
+ .root_source_file = b.path(options.root_src),
.optimize = test_target.optimize_mode,
.target = resolved_target,
.max_rss = max_rss,
@@ -1046,7 +1046,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
.single_threaded = test_target.single_threaded,
.use_llvm = test_target.use_llvm,
.use_lld = test_target.use_lld,
- .zig_lib_dir = .{ .path = "lib" },
+ .zig_lib_dir = b.path("lib"),
.pic = test_target.pic,
.strip = test_target.strip,
});
@@ -1062,7 +1062,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
const use_lld = if (test_target.use_lld == false) "-no-lld" else "";
const use_pic = if (test_target.pic == true) "-pic" else "";
- for (options.include_paths) |include_path| these_tests.addIncludePath(.{ .path = include_path });
+ for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path));
const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}", .{
options.name,
@@ -1084,7 +1084,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
.name = qualified_name,
.link_libc = test_target.link_libc,
.target = b.resolveTargetQuery(altered_query),
- .zig_lib_dir = .{ .path = "lib" },
+ .zig_lib_dir = b.path("lib"),
});
compile_c.addCSourceFile(.{
.file = these_tests.getEmittedBin(),
@@ -1092,9 +1092,17 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
// Tracking issue for making the C backend generate C89 compatible code:
// https://github.com/ziglang/zig/issues/19468
"-std=c99",
- "-pedantic",
"-Werror",
+ "-Wall",
+ "-Wembedded-directive",
+ "-Wempty-translation-unit",
+ "-Wextra",
+ "-Wgnu",
+ "-Winvalid-utf8",
+ "-Wkeyword-macro",
+ "-Woverlength-strings",
+
// Tracking issue for making the C backend generate code
// that does not trigger warnings:
// https://github.com/ziglang/zig/issues/19467
@@ -1103,17 +1111,17 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
"-Wno-builtin-requires-header",
// spotted on linux
- "-Wno-gnu-folding-constant",
- "-Wno-incompatible-function-pointer-types",
- "-Wno-incompatible-pointer-types",
- "-Wno-overlength-strings",
+ "-Wno-braced-scalar-init",
+ "-Wno-excess-initializers",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-unused",
+ "-Wno-unused-parameter",
// spotted on darwin
- "-Wno-dollar-in-identifier-extension",
- "-Wno-absolute-value",
+ "-Wno-incompatible-pointer-types",
},
});
- compile_c.addIncludePath(.{ .path = "lib" }); // for zig.h
+ compile_c.addIncludePath(b.path("lib")); // for zig.h
if (target.os.tag == .windows) {
if (true) {
// Unfortunately this requires about 8G of RAM for clang to compile
@@ -1189,7 +1197,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
if (c_abi_target.use_lld == false) "-no-lld" else "",
if (c_abi_target.pic == true) "-pic" else "",
}),
- .root_source_file = .{ .path = "test/c_abi/main.zig" },
+ .root_source_file = b.path("test/c_abi/main.zig"),
.target = resolved_target,
.optimize = optimize_mode,
.link_libc = true,
@@ -1199,7 +1207,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
.strip = c_abi_target.strip,
});
test_step.addCSourceFile(.{
- .file = .{ .path = "test/c_abi/cfuncs.c" },
+ .file = b.path("test/c_abi/cfuncs.c"),
.flags = &.{"-std=c99"},
});
for (c_abi_target.c_defines) |define| test_step.defineCMacro(define, null);
diff --git a/tools/update_crc_catalog.zig b/tools/update_crc_catalog.zig
index 0e8d9b3ef8..31d0b55e1b 100644
--- a/tools/update_crc_catalog.zig
+++ b/tools/update_crc_catalog.zig
@@ -23,11 +23,15 @@ pub fn main() anyerror!void {
var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
defer zig_src_dir.close();
- const target_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash", "crc" });
- var target_dir = try zig_src_dir.makeOpenPath(target_sub_path, .{});
- defer target_dir.close();
+ const hash_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash" });
+ var hash_target_dir = try zig_src_dir.makeOpenPath(hash_sub_path, .{});
+ defer hash_target_dir.close();
- var zig_code_file = try target_dir.createFile("catalog.zig", .{});
+ const crc_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash", "crc" });
+ var crc_target_dir = try zig_src_dir.makeOpenPath(crc_sub_path, .{});
+ defer crc_target_dir.close();
+
+ var zig_code_file = try hash_target_dir.createFile("crc.zig", .{});
defer zig_code_file.close();
var cbw = std.io.bufferedWriter(zig_code_file.writer());
@@ -37,15 +41,23 @@ pub fn main() anyerror!void {
try code_writer.writeAll(
\\//! This file is auto-generated by tools/update_crc_catalog.zig.
\\
- \\const Crc = @import("../crc.zig").Crc;
+ \\const impl = @import("crc/impl.zig");
+ \\
+ \\pub const Crc = impl.Crc;
+ \\pub const Polynomial = impl.Polynomial;
+ \\pub const Crc32WithPoly = impl.Crc32WithPoly;
+ \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly;
+ \\
+ \\// IEEE is by far the most common CRC and so is aliased by default.
+ \\pub const Crc32 = Crc32WithPoly(.IEEE);
\\
\\test {
- \\ _ = @import("catalog_test.zig");
+ \\ _ = @import("crc/test.zig");
\\}
\\
);
- var zig_test_file = try target_dir.createFile("catalog_test.zig", .{});
+ var zig_test_file = try crc_target_dir.createFile("test.zig", .{});
defer zig_test_file.close();
var tbw = std.io.bufferedWriter(zig_test_file.writer());
@@ -57,7 +69,26 @@ pub fn main() anyerror!void {
\\
\\const std = @import("std");
\\const testing = std.testing;
- \\const catalog = @import("catalog.zig");
+ \\const verify = @import("../verify.zig");
+ \\const crc = @import("../crc.zig");
+ \\
+ \\test "crc32 ieee" {
+ \\ inline for ([2]type{ crc.Crc32WithPoly(.IEEE), crc.Crc32SmallWithPoly(.IEEE) }) |ieee| {
+ \\ try testing.expect(ieee.hash("") == 0x00000000);
+ \\ try testing.expect(ieee.hash("a") == 0xe8b7be43);
+ \\ try testing.expect(ieee.hash("abc") == 0x352441c2);
+ \\ try verify.iterativeApi(ieee);
+ \\ }
+ \\}
+ \\
+ \\test "crc32 castagnoli" {
+ \\ inline for ([2]type{ crc.Crc32WithPoly(.Castagnoli), crc.Crc32SmallWithPoly(.Castagnoli) }) |casta| {
+ \\ try testing.expect(casta.hash("") == 0x00000000);
+ \\ try testing.expect(casta.hash("a") == 0xc1d04330);
+ \\ try testing.expect(casta.hash("abc") == 0x364b3fb7);
+ \\ try verify.iterativeApi(casta);
+ \\ }
+ \\}
\\
);
@@ -146,7 +177,7 @@ pub fn main() anyerror!void {
try test_writer.writeAll(try std.fmt.allocPrint(arena,
\\
\\test "{0s}" {{
- \\ const {1s} = catalog.{1s};
+ \\ const {1s} = crc.{1s};
\\
\\ try testing.expectEqual(@as(u{2s}, {3s}), {1s}.hash("123456789"));
\\